physop.red 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488
  1. module physop;
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % %
  4. % P H Y S O P %
  5. % %
  6. % A Package for Operator Calculus %
  7. % in Physics %
  8. % %
  9. % Author: Mathias Warns %
  10. % Physics Institute %
  11. % University of Bonn %
  12. % Nussallee 12 %
  13. % D-5300 BONN 1 (F.R.G.) %
  14. % <UNP008@DBNRHRZ1.bitnet> %
  15. % %
  16. % Version: 1.5 06 Jan 1992 %
  17. % %
  18. % Designed for: REDUCE version 3.4 %
  19. % Tested on : - Intel 386/486 AT compatible computers %
  20. % PSL implementation of REDUCE 3.4 %
  21. % - IBM 3084/9000-620 MVS/XA %
  22. % PSL implementation of REDUCE 3.4 %
  23. % %
  24. % CAUTION: (i) The NONCOM2 package is needed to run this package %
  25. % (ii) This package cannot be used simultaneously with %
  26. % packages modifying the standard GETRTYPE procedure %
  27. % %
  28. % Copyright (c) Mathias Warns 1990 - 1992 %
  29. % %
  30. % Permission is granted to any individual or institution to %
  31. % use, copy or re-distribute this software as long as it is %
  32. % not sold for profit, provided that this copyright notice %
  33. % is retained and the file is not altered. %
  34. % %
  35. % *** Revision history since issue of Version 0.99 *** %
  36. % %
  37. % - sloppy use of CAR on atoms corrected in various procedures %
  38. % - MUL and TSTACK added in PHYSOPTIMES %
  39. % - Bug in CLEARPHYSOP corrected %
  40. % - ordering procedures recoded for greater efficiency %
  41. % - handling of PROG expressions included via %
  42. % procedure PHYSOPPROG %
  43. % - procedures PHYSOPTIMES and MULTOPOP!* modified %
  44. % - extended error handling inclued via REDERR2 %
  45. % - PHYSOPTYPELET recoded %
  46. % - PHYSOPCONTRACT modified for new pattern natcher %
  47. % - EQ changed to = in MULTF and MULTFNC %
  48. % - PHYSOPCOMMUTE/PHYSOPANTICOMMUTE and COMM2 corrected %
  49. % - Handling of SUB and output printing adapted to 3.4 %
  50. % %
  51. % 1.1 130791 mw %
  52. % - Modifications for greater efficiency in procedures ORDOP, %
  53. % ISANINDEX and ISAVARINDEX %
  54. % - PHYSOP2SQ slightly modified for greater efficiency %
  55. % - Procedure COLLECTPHYSTYPE added %
  56. % - handling of inverse and adjoint operators modified %
  57. % procedures INV and ADJ2 modified %
  58. % procedures INVP and ADJP recoded %
  59. % - procedures GETPHYSTYPE!*SQ and GETPHYSTYPESF added for greater %
  60. % efficiency in type checking of !*SQ expressions %
  61. % - procedure GETPHYTYPE modified accordingly %
  62. % - SIMP!* changed to SUBS2 in procedure PHYSOPSUBS %
  63. % - Bug in EXPTEXPAND and PHYSOPEXPT corrected %
  64. % - PHYSOPORDCHK and PHYSOPSIMP slightly enhanced %
  65. % - PHYSOPTYPELET enhanced (COND treatment) %
  66. % - phystypefn for PLUS and DIFFERENCE changed to GETPHYSTYPEALL %
  67. % - GETPHYSTYPEALL added %
  68. % - GETPHYSTYPETIMES modified %
  69. % 1.2 190891 mw %
  70. % - implementation of property PHYSOPNAME for PHYSOPs %
  71. % - procedures SCALOP,VECOP,TENSOP,STATE,INV,ADJ2,INVADJ modified %
  72. % - procedure ORDOP recoded, NCMPCHK and PHYSOPMEMBER modified %
  73. % - procedure PHYSOPSM!* enhanced %
  74. % 1.3 test implementation of a new ordering scheme 260891 mw %
  75. % - Procedure OPNUM!* and RESET!_OPNUMS added %
  76. % - procedure ORDOP recoded %
  77. % - procedure SCALOP,VECOP,TENSOP,STATE,OPORDER modified %
  78. % - procedure !*XADD added %
  79. % - procedure PHYSOPSIMP corrected %
  80. % 1.4 181291 mw %
  81. % - bug in procedures SCALOPP, PHYSOPSIMP and TENSOP corrected %
  82. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  83. create!-package('(physop),'(contrib physics));
  84. %-------------------------------------------------------%
  85. % This part has to be modified by the user if required %
  86. %-------------------------------------------------------%
  87. % input the NONCOM2 package here for a compiled version
  88. % input noncom2;
  89. load!-package 'noncom2;
  90. % Modify the infix character for the OPAPPLY function if needed
  91. newtok'((|) opapply);
  92. flag('(opapply), 'spaced);
  93. %-------------------------------------------------------%
  94. % E N D of user modifiable part %
  95. %-------------------------------------------------------%
  96. %**************** the following is needed for REDUCE 3.4 *************
  97. fluid '(!*nosq); % controls proper use of !*q2a
  98. !*nosq := t;
  99. % ************** end of 3.4 modifications **************************
  100. fluid '(frlis!* obrkp!*);
  101. newtok '((d o t) dot);
  102. flag ('(dot), 'spaced);
  103. % define some global variables from REDUCE needed in the package
  104. fluid '(alglist!* subfg!* wtl!*);
  105. Global '(tstack!* mul!*);
  106. % ---define global variables needed for the package---
  107. FLuid '(oporder!* defoporder!* physopindices!* physopvarind!*);
  108. Fluid '(physoplist!*);
  109. Global '(specoplist!*);
  110. % define global flags
  111. fluid '(!*anticom !*anticommchk !*contract !*contract2 !*hardstop);
  112. fluid '(!*indflg indcnt!* !*ncmp ncmp!*);
  113. indcnt!* := 0;
  114. % additional flag needed for contraction
  115. !*contract2 := nil;
  116. % flag indicating that one elementary comm or opapply has not
  117. % been found --> print warning message
  118. !*hardstop := nil;
  119. % this are algebraic mode switches
  120. switch contract;
  121. switch anticom;
  122. % reserved operators and variables;
  123. % idx is the basic identifier for system created indices
  124. Global '(idx);
  125. % ----- link new data type PHYSOP in REDUCE ------
  126. % physop is the new datatype containing all subtypes
  127. put('physop,'name,'physop); %datatype name
  128. put('physop,'evfn,'!*physopsm!*); % basic simplification routine
  129. put('physop,'typeletfn,'physoptypelet); % routine for type assignements
  130. % Note: we need to make gamma a regular id.
  131. remprop('gamma,'simpfn); remflag('(gamma),'full);
  132. % ----RLISP procedures which have been modified -----
  133. % procedure for extended error handling
  134. symbolic procedure rederr2(u,v);
  135. begin
  136. msgpri("Error in procedure ",u, ": ", nil,nil);
  137. rederr v
  138. end ;
  139. % procedures multf and multfnc have to be redefined to avoid
  140. % contraction of terms after exptexpand
  141. symbolic procedure multf(u,v); % changed
  142. %U and V are standard forms.
  143. %Value is standard form for U*V;
  144. begin scalar ncmp,x,y;
  145. a: if null u or null v then return nil
  146. else if u=1 then return v % ONEP
  147. else if v=1 then return u % ONEP
  148. else if domainp u then return multd(u,v)
  149. else if domainp v then return multd(v,u)
  150. else if not(!*exp or ncmp!* or wtl!* or x)
  151. then <<u := mkprod u; v := mkprod v; x := t; go to a>>;
  152. x := mvar u;
  153. y := mvar v;
  154. % if (ncmp := noncomp y) and noncomp x then return multfnc(u,v)
  155. if noncommuting(x,y) then return multfnc(u,v)
  156. % we have to put this clause here to prevent evaluation in case
  157. % of equal main vars
  158. else if noncommutingf(y, lc u) or (ordop(x,y) and (x neq y))
  159. then << x := multf(lc u,v);
  160. y := multf(red u,v);
  161. return if null x then y else lpow u .* x .+ y>>
  162. else if x = y and (not physopp x or !*contract2)
  163. % two forms have the same mvars
  164. % switch contract added here to inhibit power contraction
  165. % if not wanted (used by PHYSOP)
  166. then << x := mkspm(x,ldeg u+ldeg v);
  167. y := addf(multf(red u,v),multf(!*t2f lt u,red v));
  168. return if null x or null(u := multf(lc u,lc v))
  169. then <<!*asymp!* := t; y>>
  170. else if x=1 then addf(u,y)
  171. else if null !*mcd then addf(!*t2f(x .* u),y)
  172. else x .* u .+ y>>;
  173. x := multf(u,lc v);
  174. y := multf(u,red v);
  175. return if null x then y else lpow v .* x .+ y
  176. end;
  177. symbolic procedure multfnc(u,v);
  178. %returns canonical product of U and V, with both main vars non-
  179. %commutative;
  180. begin scalar x,y;
  181. x := multf(lc u,!*t2f lt v);
  182. if null x
  183. then return addf(multf(red u,v),multf(!*t2f lt u,red v));
  184. % switch contract added here to avoid contraction of equal powers
  185. % used by PHYSOP
  186. return addf((if not domainp x and (mvar x = mvar u) and
  187. ((not physopp mvar x) or !*contract2)
  188. then addf(if null (y := mkspm(mvar u,ldeg u+ldeg v))
  189. then nil
  190. else if y = 1 then lc x
  191. else !*t2f(y .* lc x),
  192. multf(!*p2f lpow u,red x))
  193. else !*t2f(lpow u .* x)),
  194. addf(multf(red u,v),multf(!*t2f lt u,red v)))
  195. end;
  196. symbolic procedure opmtch!* u;
  197. % same as opmtch but turns subfg!* on
  198. begin scalar x,flg;
  199. flg:= subfg!*; subfg!* := t;x:= opmtch u; subfg!* := flg;
  200. return x
  201. end;
  202. symbolic procedure reval3 u;
  203. % this is just a redefinition of reval2(u,nil)
  204. % which call simp instead of simp!*
  205. % it saves at lot of writing in some procedures
  206. mk!*sq x where x := simp u;
  207. % ---- procedure related to ordering of physops in epxr -------
  208. symbolic procedure oporder u;
  209. % define a new oporder list
  210. begin
  211. if not listp u then rederr2('oporder, "invalid argument to oporder");
  212. if (u = '(nil)) then oporder!* := defoporder!* % default list
  213. else for each x in reverse u do <<
  214. if not physopp x then rederr2('oporder,
  215. list(x," is not a PHYSOP"));
  216. oporder!* := nconc(list(x),physopdelete(x,oporder!*)) >>; %1.01
  217. % write "oporder!* set to: ",oporder!*;terpri();
  218. reset!_opnums(); %1.03
  219. rmsubs()
  220. end;
  221. rlistat '(oporder);
  222. symbolic procedure physopdelete(u,v);
  223. % u is a physop, v is a list of physops
  224. % deletes u from v
  225. if atom u then delete(u,v)
  226. else
  227. delete(u,delete(car u,delete(removeindices(u,collectindices u),v)));
  228. symbolic procedure opnum!* u; % new 1.03
  229. begin scalar op,arglist;
  230. if not idp u then u := removeindices(u,collectindices u);
  231. if idp u then op := u
  232. else << op := car u; arglist := cdr u;>>;
  233. return
  234. if null (u:= assoc(arglist,get(op,'opnum))) then
  235. cdr assoc(nil,get(op,'opnum))
  236. else cdr u
  237. end;
  238. symbolic procedure reset!_opnums();
  239. begin scalar x,lst,n,op,arglist;
  240. lst := oporder!*;
  241. n := 1;
  242. a: if null lst then return;
  243. x := car lst; lst := cdr lst;
  244. if idp x then <<op := x; arglist := nil>>
  245. else <<op := car x; arglist := cdr x>>;
  246. put(op,'opnum,!*xadd((arglist . n),get(op,'opnum)));
  247. n:= n+1;
  248. go to a
  249. end;
  250. symbolic procedure !*xadd(u,v); % new 1.03
  251. % u is assignement , v is a table
  252. % returns updated table
  253. begin scalar x;
  254. x := v;
  255. while x and not (car u = caar x) do x := cdr x;
  256. if x then v := delete(car x,v);
  257. v := u . v;
  258. return v
  259. end;
  260. symbolic procedure ordop(u,v);
  261. % recoded ordering procedure of operators
  262. % checks new list oporder!* for physops or calls ordop2
  263. % default is to put anything ahead of physops
  264. % we use !*physopp instead of physopp in order to use
  265. % ordop even if we hide the physop rtype
  266. begin scalar x,y,z,nx,ny;
  267. % this are the trivial cases
  268. if not (!*physopp u and !*physopp v) then return
  269. if !*physopp u then nil
  270. else if !*physopp v then t
  271. else ordop2(u,v);
  272. % now come the cases with 2 physops
  273. % following section modified 1.02
  274. if idp u then x:= get(u,'physopname)
  275. else
  276. <<
  277. x:=get(car u,'physopname);
  278. x:= x . cdr u;
  279. u := car u;
  280. >>;
  281. if member(u,specoplist!*) then return t;
  282. if idp v then y:= get(v,'physopname)
  283. else
  284. <<
  285. y:= get(car v, 'physopname);
  286. y := y . cdr v;
  287. v := car v;
  288. >>;
  289. if member(v,specoplist!*) then return t;
  290. % end of modifications 1.02
  291. % from here it is 1.03
  292. nx := opnum!* x;
  293. ny := opnum!* y;
  294. return
  295. if nx < ny then t
  296. else if nx > ny then nil
  297. else if idp x then t
  298. else if idp y then nil
  299. else ordop(cdr x, cdr y);
  300. end;
  301. symbolic procedure ordop2(u,v);
  302. % this is nothing but the standard ordop procedure
  303. begin scalar x;
  304. x := kord!*;
  305. a: if null x then return ordp(u,v)
  306. else if u eq car x then return t
  307. else if v eq car x then return;
  308. x := cdr x;
  309. go to a
  310. end;
  311. % obsolete in 1.03
  312. %symbolic procedure physopmember(u,v); % 1.02 order modified
  313. % u is a physop, v is a list
  314. % return part of v starting with u
  315. %member(u,v) or ((not atom u) and (member(car u,v)
  316. % or member(removeindices(u,collectindices u),v)));
  317. symbolic procedure physopordchk(u,v); % new version 080591
  318. % u and v are physopexpr
  319. % builds up a list of physops of u and v
  320. % checks if there is a pair of wrong ordered noncommuting operators
  321. % in these lists
  322. begin scalar x,y,z,oplist,lst;
  323. x := deletemult!* !*collectphysops u; %1.01
  324. y := deletemult!* !*collectphysops v; % 1.01
  325. return
  326. if null x then t
  327. else if null y then nil
  328. else if member('unit,x) or member('unit,y) then nil %further eval needed
  329. else physopordchk!*(x,y);
  330. end;
  331. symbolic procedure ncmpchk(x,y); % order changed 1.02
  332. % x and y are physops
  333. % checks for correct ordering in noncommuting case
  334. (not noncommuting(x,y)) or ordop(x,y);
  335. symbolic procedure physopordchk!*(u,v);
  336. % u and v are lists of physops
  337. % checks if there is a pair of wrong ordered noncommuting operators
  338. % in this list
  339. begin scalar x,y,lst;
  340. x:= car u; u := cdr U;
  341. if null u then
  342. if null cdr v then
  343. return (ncmpchk(x,car v) and not (invp x = car v))
  344. else
  345. <<
  346. lst := for each y in v collect ncmpchk(x,y);
  347. if member(nil,lst) then return nil
  348. else return t
  349. >>
  350. else return (physopordchk!*(list(x),v) and physopordchk!*(u,v));
  351. end;
  352. % ---general testing functions for PHYSOP expressions----
  353. symbolic procedure physopp u;
  354. if atom u then (idp u and (get(u,'rtype) eq 'physop))
  355. else (idp car u and (get(car u,'rtype) eq 'physop));
  356. % slightly more general
  357. symbolic procedure !*physopp u;
  358. % used to determine physops when physop rtype is hidden
  359. if atom u then (idp u and get(u,'phystype))
  360. else (idp car u and get(car u,'phystype));
  361. symbolic procedure physopp!* u;
  362. physopp u or (not atom u and (flagp(car u,'physopfn) or
  363. (flagp(car u,'physoparith) and
  364. hasonephysop cdr u) or (flagp(car u,'physopmapping) and
  365. hasonephysop cdr u)));
  366. symbolic procedure !*physopp!* u;
  367. physopp!* u or getphystype u;
  368. symbolic procedure hasonephysop u;
  369. if null u then nil
  370. else (physopp!* car u) or hasonephysop cdr u;
  371. symbolic procedure areallphysops u;
  372. if null u then nil
  373. else if null cdr u then !*physopp!* car u
  374. else (!*physopp!* car u) and areallphysops cdr u;
  375. % *****defining functions for different data subtypes******
  376. % scalar operator
  377. symbolic procedure scalop u;
  378. begin scalar y;
  379. for each x in u do
  380. if not idp x then
  381. msgpri("cannot declare",x,"a scalar operator",nil,nil)
  382. else if physopp x then
  383. msgpri(x,"already declared as",get(x,'phystype),nil,nil)
  384. else <<y :=gettype x;
  385. if y memq '(matrix operator array procedure) then
  386. msgpri(x,"already defined as",y,nil,nil)
  387. else <<
  388. put(x,'rtype,'physop);
  389. put(x,'phystype,'scalar);
  390. put(x,'psimpfn,'physopsimp);
  391. put(x,'physopname,x); % 1.02
  392. defoporder!* := nconc(defoporder!*,list(x));
  393. oporder!* := nconc(oporder!*,list(x));
  394. physoplist!* := nconc(physoplist!*,list(x));
  395. invphysop x; adj2 x; invadj x; %1.01
  396. reset!_opnums(); %1.03
  397. >>;
  398. >>;
  399. return nil
  400. end;
  401. symbolic procedure scalopp u;
  402. (idp u and get(u,'phystype) = 'scalar) or (not atom u and (
  403. (get(car u,'phystype) = 'scalar) or
  404. ((get(car u,'phystype) = 'vector) and isanindex cadr u)
  405. or ((get(car u,'phystype) = 'tensor) and
  406. (length(cdr u) >= get(car u,'tensdimen)) and
  407. areallindices(for k:=1 :get(car u,'tensdimen) collect nth(cdr u,k)))));
  408. symbolic procedure vecop u;
  409. begin scalar y;
  410. for each x in u do
  411. if not idp x then
  412. msgpri("cannot declare",x,"a vector operator",nil,nil)
  413. else if physopp x then
  414. msgpri(x,"already declared as",get(x,'phystype),nil,nil)
  415. else <<y :=gettype x;
  416. if y memq '(matrix operator array procedure) then
  417. msgpri(x,"already defined as",y,nil,nil)
  418. else <<put(x,'rtype,'physop);
  419. put(x,'phystype,'vector);
  420. put(x,'psimpfn,'physopsimp);
  421. put(x,'physopname,x); % 1.02
  422. defoporder!* := nconc(defoporder!*,list(x));
  423. oporder!* := nconc(oporder!*,list(x));
  424. physoplist!* := nconc(physoplist!*,list(x));
  425. invphysop x; adj2 x; invadj x; %1.01
  426. reset!_opnums();
  427. >>;
  428. >>;
  429. return nil
  430. end;
  431. symbolic procedure vecopp u;
  432. (idp u and (get(u,'phystype) = 'vector)) or (not atom u and
  433. ((get(car u,'phystype) ='vector) and not isanindex cadr u));
  434. symbolic procedure tensop u;
  435. begin scalar y,n;
  436. % write "car u=",car u;terpri();
  437. for each x in u do
  438. <<
  439. if idp x or not numberp cadr x then
  440. msgpri("Tensor operator",x,"declared without dimension",nil,nil)
  441. else
  442. <<
  443. n:= cadr x; x:= car x;
  444. if not idp x then
  445. msgpri("cannot declare",x,"a tensor operator",nil,nil)
  446. else if physopp x then
  447. msgpri(x,"already declared as",get(x,'phystype),nil,nil)
  448. else
  449. <<
  450. y :=gettype x;
  451. if y memq '(matrix operator array procedure) then
  452. msgpri(x,"already defined as",y,nil,nil)
  453. else
  454. <<
  455. put(x,'rtype,'physop);
  456. put(x,'phystype,'tensor);
  457. put(x,'psimpfn,'physopsimp);
  458. put(x,'physopname,x); % 1.02
  459. put(x,'tensdimen,n);
  460. defoporder!* := nconc(defoporder!*,list(x));
  461. oporder!* := nconc(oporder!*,list(x));
  462. physoplist!* := nconc(physoplist!*,list(x));
  463. invphysop x; adj2 x; invadj x; %1.01
  464. reset!_opnums();
  465. >>
  466. >>
  467. >>
  468. >>;
  469. return nil
  470. end;
  471. symbolic procedure tensopp u;
  472. (idp u and (get(u,'phystype) = 'tensor)) or (not atom u and
  473. ((get(car u,'phystype) ='tensor) and not isanindex cadr u));
  474. symbolic procedure state u;
  475. begin scalar y;
  476. for each x in u do
  477. if not idp x then msgpri("cannot declare",x,"a state",nil,nil)
  478. else if physopp x then
  479. msgpri(x,"already declared as",get(x,'phystype),nil,nil)
  480. else <<y :=gettype x;
  481. if y memq '(matrix operator array procedure) then
  482. msgpri(x,"already defined as",y,nil,nil)
  483. else <<put(x,'rtype,'physop);
  484. put(x,'phystype,'state);
  485. put(x,'psimpfn,'physopsimp);
  486. put(x,'physopname,x); % 1.02
  487. defoporder!* := nconc(defoporder!*,list(x));
  488. oporder!* := nconc(oporder!*,list(x));
  489. physoplist!* := nconc(physoplist!*,list(x));
  490. adj2 x;
  491. reset_opnums(); % 1.03
  492. >>
  493. >>;
  494. return nil
  495. end;
  496. symbolic procedure statep u;
  497. (idp u and get(u,'phystype) = 'state) or (not atom u and
  498. (idp car u and get(car u,'phystype) = 'state));
  499. symbolic procedure statep!* u;
  500. % slightly more general since state may be hidden in another operator
  501. (getphystype u = 'state);
  502. % some procedures for vecop and tensop indices
  503. symbolic procedure physindex u;
  504. begin scalar y;
  505. for each x in u do <<
  506. if not idp x then msgpri("cannot declare",x,"an index",nil,nil)
  507. else if physopp x then
  508. msgpri(x,"already declared as",get(x,'phystype),nil,nil)
  509. else <<y :=gettype x;
  510. if y memq '(matrix operator array procedure) then
  511. msgpri(y,"already defined as",y,nil,nil)
  512. else putanewindex x >>
  513. >>;
  514. return nil
  515. end;
  516. symbolic procedure physindexp u;
  517. % boolean function to test if an id is a physindex
  518. % in algebraic mode
  519. if idp u and isanindex u then t
  520. else if idlistp u and areallindices u then t
  521. else nil;
  522. flag ('(physindexp),'opfn);
  523. flag ('(physindexp),'boolean);
  524. deflist('((scalop rlis) (vecop rlis) (tensop rlis)
  525. (state rlis) (physindex rlis)),'stat);
  526. symbolic procedure isanindex u; %recoded 1.01
  527. idp u and (memq(u,physopindices!*) or member(u,physopvarind!*)
  528. or (memq(u,frlis!*) and member(revassoc(u,frasc!*),
  529. physopindices!*)));
  530. symbolic procedure isavarindex u; % recoded 1.01
  531. member(u,physopvarind!*);
  532. symbolic procedure areallindices u;
  533. isanindex car u and (null cdr u or areallindices cdr u);
  534. symbolic procedure putanewindex u;
  535. % makes a new index available to the system
  536. begin scalar indx;
  537. indx := u;
  538. if isanindex indx then nil
  539. else if (not atom indx) or getrtype indx then
  540. rederr2('putanewindex,list(indx,"is not an index"))
  541. else physopindices!* := nconc(physopindices!*,list(indx));
  542. return nil
  543. end;
  544. symbolic procedure putanewindex!* u;
  545. % used by ISANINDEX to recognize unresolved IDXn indices
  546. begin scalar x;
  547. if not idp u then return;
  548. x:= explode u;
  549. if length(x) < 4 then return;
  550. x := for j:= 1 : 3 collect nth(x,j);
  551. if not(x='(I D X ) or x='(!i !d !x)) then return; % check both cases.
  552. physopindices!* := nconc(physopindices!*,list(u));
  553. return t
  554. end;
  555. symbolic procedure makeanewindex();
  556. % generates a new index
  557. begin scalar x,n;
  558. n:=0;
  559. a: n:=n+1;
  560. x:= mkid('idx,n);
  561. if isanindex x then go to a
  562. else putanewindex x;
  563. return x
  564. end;
  565. symbolic procedure makeanewvarindex();
  566. % generates a new variable index
  567. % for patterm matching
  568. % physopvarind!* keeps var indices to avoid inflation
  569. begin scalar x,y,n;
  570. n:=0;
  571. y:= makeanewindex();
  572. x := intern compress append(explode '!=,explode y);
  573. nconc(frlis!*,list(x));
  574. physopvarind!*:= nconc(physopvarind!*,list(x));
  575. frasc!* := nconc(frasc!*,list((y . x)));
  576. return x
  577. end;
  578. symbolic procedure getvarindex n;
  579. begin scalar ilen;
  580. if not numberp n then rederr2 ('getvarindex,
  581. "invalid argument to getvarindex");
  582. ilen := length(physopvarind!*);
  583. return
  584. if n > ilen then makeanewvarindex()
  585. else nth(physopvarind!*,n);
  586. end;
  587. symbolic procedure transformvarindex u;
  588. % u is a free index
  589. % looks for the corresponding index on the frasc
  590. % or creates a new one
  591. begin scalar x;
  592. x := explode u;
  593. if length(x) < 3 or not(nth(x,2) eq '=) then return u;
  594. x := intern compress pnth(x,3);
  595. putanewindex x;
  596. if not atsoc(x,frasc!*) then
  597. frasc!* := nconc(frasc!*,list((x . u)));
  598. return x
  599. end;
  600. symbolic procedure insertindices(u,x);
  601. % u is a vecopp or tensopp
  602. % x is an index or a list of indices
  603. if (idp x and not isanindex x) or (idlistp x and not areallindices x)
  604. then rederr2('insertindices, "invalid indices to insertindex")
  605. else if vecopp u then if idp u then list(u,x)
  606. else car u . ( x . cdr u)
  607. else if tensopp u then if idp u then u . x
  608. else car u . nconc(x,cdr u)
  609. % do not insert any index in states or scalops
  610. else u;
  611. symbolic procedure insertfreeindices(u,flg);
  612. % procedure to transform vecop and tensop into scalops
  613. % by inserting free indices taken from the varindlist
  614. % flg is set to t if variable indices are requested
  615. begin scalar n,x;
  616. if vecopp u then <<x:= if flg then
  617. transformvarindex getvarindex(indcnt!* + 1)
  618. else getvarindex(indcnt!* + 1);
  619. return insertindices(u,x)>>
  620. else if tensopp u then <<n:= get(u,'tensdimen);
  621. x:= for k:=1 :n collect if flg then
  622. transformvarindex getvarindex(indcnt!* +k)
  623. else getvarindex(indcnt!* +k);
  624. return insertindices(u,x) >>
  625. else rederr2('insertfreeindices,
  626. "invalid argument to insertfreeindices");
  627. end;
  628. symbolic procedure collectindices u;
  629. % makes a list of all indices in a.e. u
  630. begin scalar v,x;
  631. if atom u then
  632. if isanindex u then return list(u)
  633. else return nil;
  634. a: v := car u;
  635. u := cdr u;
  636. x :=nconc(x,collectindices v);
  637. if null u then return x;
  638. go to a
  639. end;
  640. symbolic procedure removeindices(u,x);
  641. % u is physop (scalop) containing physindices
  642. % x is an index or a list of indices
  643. begin scalar op;
  644. trwrite('removeindices,"u= ",u," x= ",x);
  645. if null x or idp u or not !*physopp u then return u;
  646. if (idp x and not isanindex x) or (idlistp x and not areallindices x)
  647. then rederr2('removeindices, "invalid arguments to removeindices");
  648. op:=car u;u := cdr u;
  649. if null u then return op;
  650. if idp x then u := delete(x,u)
  651. else for each y in x do u:= delete(y,u);
  652. return if null u then op else op . u
  653. end;
  654. symbolic procedure deadindices u;
  655. % checks an a.e. u to see if there are dead indices
  656. % i.e. indices appearing twice or more
  657. %returns the list of dead indices in u
  658. begin scalar x,res;
  659. if null u or atom u then return nil;
  660. x := collectindices u;
  661. for each y in x do
  662. if memq(y,memq(y,x)) then res :=nconc(res,list(y));
  663. return res
  664. end;
  665. symbolic procedure collectphysops u;
  666. % makes a list of all physops in a.e. u
  667. begin scalar v,x;
  668. if atom u then
  669. if physopp u then return list(u)
  670. else return nil
  671. else if physopp u then return list(removeindices(u,collectindices u));
  672. a: v := car u;
  673. u := cdr u;
  674. x :=nconc(x,collectphysops v);
  675. if null u then return x;
  676. go to a
  677. end;
  678. symbolic procedure !*collectphysops u;
  679. % makes a list of all physops in a.e. u
  680. % with ALL indices
  681. begin scalar v,x;
  682. if physopp u then return list(u);
  683. if atom u then return nil;
  684. a: v := car u;
  685. u := cdr u;
  686. x :=nconc(x,!*collectphysops v);
  687. if null u then return x;
  688. go to a
  689. end;
  690. symbolic procedure collectphysops!* u;
  691. begin scalar x;
  692. x:= for each y in collectphysops u collect if idp y then y
  693. else car y;
  694. return x
  695. end;
  696. symbolic procedure collectphystype u; % new 1.01
  697. % makes a list of all physops in u
  698. % with ALL indices
  699. if physopp u then list(getphystype u)
  700. else if atom u then nil
  701. else deletemult!* (for each v in u collect getphystype v);
  702. % ---- PHYSOP procedures for type check and assignement ----
  703. % modify the REDUCE GETRTYPE routine to get control over PHYSOP
  704. % expressions
  705. symbolic procedure getrtype u; %modified
  706. % Returns overall algebraic type of u (or NIL if expression is a
  707. % scalar). Analysis is incomplete for efficiency reasons.
  708. % Type conflicts will later be resolved when expression is evaluated.
  709. begin scalar x,y;
  710. return
  711. if atom u
  712. then if not idp u then nil
  713. else if flagp(u,'share) then getrtype eval u
  714. else if x := get(u,'rtype)
  715. then if y := get(x,'rtypefn) then apply1(y,nil)
  716. else x
  717. else nil
  718. else if not idp car u then nil
  719. else if physopp!* u then 'physop % added
  720. else if (x := get(car u,'rtype)) and (x := get(x,'rtypefn))
  721. then apply1(x, cdr u)
  722. else if x := get(car u,'rtypefn) then apply1(x, cdr u)
  723. else nil
  724. end;
  725. symbolic procedure getrtypecadr u;
  726. not atom u and getrtype cadr u;
  727. symbolic procedure getnewtype u;
  728. not atom u and get(car u,'newtype);
  729. symbolic procedure getphystype u;
  730. % to get the type of a PHYSOP object
  731. begin scalar x;
  732. return
  733. if physopp u then
  734. if scalopp u then 'scalar
  735. else if vecopp u then 'vector
  736. else if tensopp u then 'tensor
  737. else if statep u then 'state
  738. else nil
  739. else if atom u then nil
  740. % following line suppressed 1.01
  741. % else if car u = '!*sq then return getphystype physopaeval u
  742. else if (x:=get(car u,'phystype)) then x
  743. else if (x:=get(car u,'phystypefn)) then
  744. apply1(x,cdr u)
  745. % from here it is 1.01
  746. else if null (x := collectphystype u) % 1.01
  747. then nil
  748. else if null cdr x then car x
  749. else if member('state,x) then 'state
  750. else rederr2('getphystype,list(
  751. "PHYSOP type conflict in",u));
  752. end;
  753. symbolic procedure getphystypecar u;
  754. not atom u and getphystype car u;
  755. symbolic procedure getphystypeor u;
  756. not atom u and (getphystype car u or getphystypeor cdr u);
  757. symbolic procedure getphystypeall args; % new 1.01
  758. begin scalar x;
  759. if null (x := collectphystype deleteall(0,args)) then
  760. return nil
  761. else if cdr x then
  762. rederr2('getphystypeall,
  763. list("PHYSOP type mismatch in",args))
  764. else return car x
  765. end;
  766. % ***** dirty trick *****
  767. % we introduce a rtypefn for !*sq expressions to get
  768. % proper type checking in assignements
  769. symbolic procedure physop!*sq U;
  770. % u is a !*sq expressions
  771. % checks if u contains physops
  772. begin scalar x;
  773. x:= !*collectphysops !*q2a car u;
  774. return
  775. if null x then nil
  776. else 'physop
  777. end;
  778. deflist('((!*sq physop!*sq)), 'rtypefn);
  779. % 1.01 we add also a phystypefn for !*sq
  780. symbolic procedure getphystype!*sq u; % new 1.01
  781. getphystypesf caar u;
  782. deflist('((!*sq getphystype!*sq)), 'phystypefn);
  783. symbolic procedure getphystypesf u; % new 1.01
  784. % u is a s.f.
  785. % returns the phystype of u
  786. if null u or domain!*p u then nil
  787. else getphystype mvar u or getphystypesf lc u;
  788. %-----end of 1.01 modifications -----------------
  789. % we have also to modify the simp!*sq routine since
  790. % there is no type checking included
  791. symbolic procedure physopsimp!*sq u;
  792. if cadr u then car u
  793. else if physop!*sq u then physop2sq physopsm!* !*q2a car u
  794. else resimp car u;
  795. put('!*sq,'simpfn,'physopsimp!*sq);
  796. % ***** end of dirty trick ******
  797. % ----PHYSOP evaluation and simplification procedures----
  798. symbolic procedure !*physopsm!* (u,v);
  799. % u is the PHYSOP expression to simplify
  800. begin scalar x,contractflg;
  801. % if contract is set to on we keep its value at the top level
  802. % (first call to physopsm) and set it to nil;
  803. contractflg:=!*contract;!*contract := nil;
  804. !*hardstop := nil;
  805. if physopp u then
  806. if (x:= get(u,'rvalue)) then u := physopaeval x
  807. else if idp u then return u
  808. else if x:=get(car u,'psimpfn) then u:= apply1(x,u)
  809. else return physopsimp u;
  810. u:= physopsm!* u;
  811. if !*hardstop then <<
  812. write " *************** WARNING: ***************";terpri();
  813. write "Evaluation incomplete due to missing elementary relations";
  814. terpri();
  815. return u>>;
  816. % the next step is to do substitutions if there are someones on
  817. % the matching lists
  818. if !*match or powlis1!* then <<
  819. u := physopsubs u;
  820. % now eval u with the substitutions
  821. u := physopsim!* u; >>;
  822. if not contractflg then return u
  823. else <<
  824. !*contract:=contractflg;
  825. return physopcontract u >>
  826. end;
  827. symbolic procedure physopsim!* u;
  828. if !*physopp!* u then physopsm!* u else u;
  829. symbolic procedure physop2sq u; %modified 1.01
  830. % u is a physop expr
  831. % returns standard quotient of evaluated u
  832. begin scalar x;
  833. return
  834. if physopp u then if (x:= get(u,'rvalue)) then physop2sq x
  835. else if idp u then !*k2q u
  836. else if (x:= get(car u,'psimpfn)) then
  837. if physopp (x:=apply1(x,u)) then
  838. !*k2q x
  839. else cadr physopsm!* x
  840. else if get(car u,'opmtch) and
  841. (x:= opmtch!* u) then physop2sq x
  842. else !*k2q u
  843. else if atom u then simp u % added 1.01
  844. else if car u eq '!*sq then cadr u
  845. else if null getphystype u then simp u % moved from top 1.01
  846. else physop2sq physopsm!* u
  847. end;
  848. symbolic procedure physopsm!* u;
  849. % basic simplification routine
  850. begin scalar oper,args,y,v,physopflg;
  851. % the following is 1.02
  852. if (null u or numberp u) then v := u
  853. else if physopp u then v:= if (y:= get(u,'rvalue)) then physopaeval y
  854. else if idp u then u
  855. else if (y:=get(car u,'psimpfn)) then
  856. apply1(y,u)
  857. else if get(car u,'opmtch) and
  858. (y:=opmtch!* u) then y
  859. else u
  860. else if atom u then v := aeval u
  861. else <<
  862. oper := car u;
  863. args := cdr u;
  864. if y:= get(oper,'physopfunction) then
  865. % this is a function which may also have normal scalar arguments
  866. % eg TIMES so we must check if args contain PHYSOP objects
  867. % or if it is an already evaluated expression of physops
  868. if flagp(oper,'physoparith) then
  869. if hasonephysop args then v:= apply(y,list args)
  870. else v := reval3 (oper . args)
  871. else if flagp(oper,'physopfn) then
  872. if areallphysops args then v:= apply(y,list args)
  873. else
  874. rederr2('physopsm!*,
  875. list("invalid call of ",oper," with args: ",args))
  876. else rederr2('physopsm!*,list(oper,
  877. " has been flagged Physopfunction"," but is not defined"))
  878. % this is for fns having a physop argument and no evaluation procedure
  879. else if flagp(oper,'physopmapping) and !*physopp!* args then
  880. v := mk!*sq !*k2q (oper . args)
  881. % special hack for handling of PROG constructs
  882. else if oper = 'PROG then v := physopprog args
  883. else v := aeval u
  884. >>;
  885. return v
  886. end;
  887. symbolic procedure physopsubs u;
  888. % general substitution routine for physop expressions
  889. % corresponds to subs2
  890. % u is a !*sq
  891. % result is u in a.e. form with all substitutions of
  892. % !*MATCH and POWLIS1!* applied
  893. % we use a quite dirty trick here which allows to use
  894. % the pattern matcher of standard REDUCE by hiding the
  895. % PHYSOP rtype temporarily
  896. begin scalar ulist,kord,alglist!*;
  897. % step 1: convert u back to an a.e.
  898. % u := physopaeval u; % 1.01 this line replaced
  899. u := physop2sq u;
  900. % step 2: transform all physops on physoplist in normal ops
  901. for each x in physoplist!* do << remprop(x,'rtype);
  902. put(x,'simpfn,'simpiden)>>;
  903. % since we need it here as a prefix op
  904. remflag('(dot),'physopfn);
  905. put('dot,'simpfn,'simpiden);
  906. % step 3: call simp!* on u
  907. % u := simp!* u; % 1.01 this line replaced
  908. u := subs2 u;
  909. % step 4: transform u back in an a.e.
  910. u := !*q2a u;
  911. % step 5: transform ops in physoplist back to physops
  912. for each x in physoplist!* do <<remprop(x,'simpfn);
  913. put(x,'rtype,'physop)>>;
  914. remprop('dot,'simpfn);
  915. flag('(dot),'physopfn);
  916. % final step return u
  917. return u
  918. end;
  919. symbolic procedure physopaeval u;
  920. % transformation of physop expression in a.e.
  921. begin scalar x;
  922. return
  923. if physopp u then
  924. if (x:=get(u,'rvalue)) then
  925. if car x eq '!*sq then !*q2a cadr x
  926. else x
  927. else if atom u then u
  928. else if (x:= get(car u,'psimpfn)) then apply1(x,u)
  929. else if get(car u,'opmtch) and (x:= opmtch!* u) then x
  930. else u
  931. else if (not atom u) and car u eq '!*sq then !*q2a cadr u
  932. else u
  933. end;
  934. symbolic procedure physopcontract u;
  935. % procedure to contract over dead indices
  936. begin scalar x,x1,w,y,z,ulist,veclist,tenslist,oldmatch,oldpowers,
  937. alglist!*,ncmplist;
  938. u := physopaeval u;
  939. if physopp u then return mk!*sq physop2sq u
  940. else if not getphystype u then return aeval u;
  941. % now came the tricky cases
  942. !*contract2 := t;
  943. % step1 : collect all physops in u
  944. ulist := collectphysops u;
  945. veclist := for each x in ulist collect if vecopp x then x else nil;
  946. tenslist := for each x in ulist collect if tensopp x then x else nil;
  947. veclist:= deletemult!* deleteall(nil,veclist);
  948. tenslist:=deletemult!* deleteall(nil,tenslist);
  949. % step2: we now modify powlis1!* and !*match
  950. oldmatch := !*match; !*match := nil;
  951. oldpowers := powlis1!*; powlis1!* := nil;
  952. % step3: transform all physops on physoplist in normal ops
  953. for each x in physoplist!* do
  954. <<
  955. remprop(x,'rtype);
  956. put(x,'simpfn,'simpiden);
  957. if noncomp!* x then ncmplist := x . ncmplist;
  958. >>;
  959. % we have to declare the ops in the specoplist as noncom to avoid
  960. % spurious simplifications during contraction
  961. remflag('(dot opapply),'physopfn); % needed here as a normal op
  962. flag(specoplist!*,'noncom);
  963. !*ncmp := t;
  964. for each x in specoplist!* do
  965. <<
  966. put(x,'simpfn,'simpiden);
  967. put(x,'noncommutes,ncmplist)
  968. >>;
  969. % step4: put new matching for each vecop on the list
  970. y := getvarindex(1);
  971. frlis!* := nconc(frlis!*,list('!=nv));
  972. frasc!* := nconc(frasc!*,list('nv . '!=nv));
  973. for each x in veclist do <<
  974. let2(list('expt,insertindices(x,transformvarindex y),'nv),
  975. list('expt,x,'nv),nil,t);
  976. x1:=delete(x,veclist);
  977. for each w in x1 do
  978. << z := list(list((insertindices(x,y) . 1),
  979. (insertindices(w,y) . 1)),(nil . t),
  980. list('dot,x,w),nil);
  981. !*match :=append(list(z),!*match) >>
  982. >>;
  983. % step4: put new matching for each tensop on the list
  984. frlis!* := nconc(frlis!*,list('!=nt));
  985. frasc!* := nconc(frasc!*,list('nt . '!=nt));
  986. for each x in tenslist do
  987. let2(list('expt,insertfreeindices(x,t),'nt),
  988. list('expt,x,'nt),nil,t);
  989. % step 6: call simp on u
  990. u := simp!* u;
  991. % step 7: restore previous settings
  992. powlis1!* := oldpowers;!*match := oldmatch;
  993. for each x in physoplist!* do
  994. <<
  995. remprop(x,'simpfn);
  996. put(x,'rtype,'physop)
  997. >>;
  998. flag('(dot opapply),'physopfn);
  999. remflag(specoplist!*,'noncom);
  1000. for each x in specoplist!* do
  1001. <<
  1002. remprop(x,'noncommutes);
  1003. remprop(x,'simpfn)
  1004. >>;
  1005. !*contract2 := nil;
  1006. return mk!*sq u
  1007. end;
  1008. symbolic procedure physopsimp u; % 1 line deleted 1.03
  1009. % procedure to simplify the arguments of a physop
  1010. % inspired from SIMPIDEN
  1011. begin scalar opname,w,x,y,flg;
  1012. if idp u then return u;
  1013. opname := car u;
  1014. x := for each j in cdr u collect
  1015. if idp j and (isanindex j or isavarindex j) then j %added 1.01
  1016. else physopsm!* j;
  1017. u := opname . for each j in x collect
  1018. if eqcar(j,'!*sq) then prepsqxx cadr J
  1019. else j;
  1020. if x := opmtch!* u then return x;
  1021. % special hack introduced here to check for
  1022. % symmetric and antisymmetric tensor operators
  1023. if scalopp u and tensopp opname then
  1024. << y := get(opname,'tensdimen);
  1025. % x is the list of physopsindices
  1026. x:= for k:=1 :y collect nth(cdr u,k);
  1027. % y contains the remaining indices
  1028. if length(cdr u) > y then y := pnth(cdr u,y+1)
  1029. else y := nil;
  1030. if flagp(opname,'symmetric) then u:= opname . ordn x
  1031. else if flagp(opname,'antisymmetric) then
  1032. << if repeats x then return 0
  1033. else if not permp(w := ordn x, x) then flg := t;
  1034. x := w;
  1035. u := opname . x >>
  1036. else u := opname . x;
  1037. if y then u:= append(u,y);
  1038. return if flg then list('minus,u) else u
  1039. >>
  1040. % special hack to introduce unrecognized IDXn indices
  1041. else if vecopp u then << if listp u then putanewindex!* cadr u;
  1042. return u >>
  1043. else if tensopp u then << if listp u then
  1044. for j:= 1 : length(cdr u) do
  1045. putanewindex!* nth(cdr u,j);
  1046. return u >>
  1047. else return u
  1048. end;
  1049. % ---- different procedures for arithmetic in phsyop expressions ----
  1050. flag('(quotient times expt difference minus plus opapply),'physoparith);
  1051. flag('(adj recip dot commute anticommute),'physopfn);
  1052. flag ('(sub),'physoparith);
  1053. flag('(sin cos tan asin acos atan sqrt int df log exp sinh cosh tanh),
  1054. 'physopmapping);
  1055. % the following is needed for correct type checking 101290 mw
  1056. symbolic procedure checkphysopmap u;
  1057. % checks an expression u for unresolved physopmapping operators
  1058. begin scalar x;
  1059. a: if null u or domain!*p u or atom u or null cdr u then return nil;
  1060. x:= car u; u:= cdr u;
  1061. if listp x and flagp(car x,'physopmapping) and hasonephysop cdr x
  1062. then return t;
  1063. go to a;
  1064. end;
  1065. symbolic procedure physopfn(oper,proc);
  1066. begin
  1067. put(oper,'physopfunction,proc);
  1068. end;
  1069. physopfn('difference,'physopdiff);
  1070. symbolic procedure physopdiff args;
  1071. begin scalar lht,rht,lhtype,rhtype;
  1072. lht := physopsim!* car args;
  1073. for each v in cdr args do <<
  1074. rht := physopsim!* v;
  1075. lhtype := getphystype lht;
  1076. rhtype := getphystype rht;
  1077. if (rhtype and lhtype) and not(lhtype eq rhtype) then
  1078. rederr2('physopdiff,"type mismatch in diff");
  1079. lht :=
  1080. mk!*sq addsq(physop2sq lht,negsq(physop2sq rht))
  1081. >>;
  1082. return lht
  1083. end;
  1084. put('difference,'phystypefn,'getphystypeall); % changed 1.01
  1085. physopfn('minus,'physopminus);
  1086. symbolic procedure physopminus arg;
  1087. begin scalar rht,rhtype;
  1088. rht := physopsim!* car arg;
  1089. rht :=
  1090. mk!*sq negsq(physop2sq rht);
  1091. return rht
  1092. end;
  1093. put('minus,'phystypefn,'getphystypecar);
  1094. physopfn('plus,'physopplus);
  1095. symbolic procedure physopplus args;
  1096. begin scalar lht,rht,lhtype,rhtype;
  1097. lht := physopsim!* car args;
  1098. for each v in cdr args do <<
  1099. rht := physopsim!* v;
  1100. lhtype := getphystype lht;
  1101. rhtype := getphystype rht;
  1102. if (rhtype and lhtype) and not (lhtype eq rhtype) then
  1103. rederr2 ('physopplus,"type mismatch in plus ");
  1104. lht :=
  1105. mk!*sq addsq(physop2sq lht,physop2sq rht)
  1106. >>;
  1107. return lht
  1108. end;
  1109. put('plus,'phystypefn,'getphystypeall); % changed 1.01
  1110. physopfn('times,'physoptimes);
  1111. symbolic procedure physoptimes args;
  1112. begin scalar lht, rht,lhtype,rhtype,x,mul;
  1113. if (tstack!* = 0) and mul!* then << mul:= mul!*; mul!* := nil; >>;
  1114. tstack!* := tstack!* + 1;
  1115. lht := physopsim!* car args;
  1116. for each v in cdr args do <<
  1117. rht :=physopsim!* v;
  1118. lhtype := getphystype lht;
  1119. rhtype := getphystype rht;
  1120. if not lhtype then
  1121. if not rhtype then lht := mk!*sq multsq(physop2sq lht,physop2sq rht)
  1122. else if zerop lht then lht := mk!*sq (nil . 1)
  1123. else if onep lht then lht:= mk!*sq physop2sq rht
  1124. else lht:= mk!*sq multsq(physop2sq lht,physop2sq rht)
  1125. else if not rhtype then lht:=
  1126. if zerop rht then mk!*sq (nil . 1)
  1127. else if onep rht then mk!*sq physop2sq lht
  1128. else mk!*sq multsq(physop2sq rht,physop2sq lht)
  1129. else if physopordchk(physopaeval lht,physopaeval rht)
  1130. and (lhtype = rhtype) and (lhtype = 'scalar)
  1131. then lht := mk!*sq multsq(physop2sq lht,physop2sq rht)
  1132. else lht:= multopop!*(lht,rht)
  1133. >>;
  1134. b: if null mul!* or tstack!* > 1 then go to c;
  1135. lht := apply1(car mul!*,lht);
  1136. mul!* := cdr mul!*;
  1137. go to b;
  1138. c: tstack!* := tstack!* - 1;
  1139. if tstack!* = 0 then mul!* := mul;
  1140. return lht
  1141. end;
  1142. put('times,'phystypefn,'getphystypetimes);
  1143. symbolic procedure getphystypetimes args; % modified 1.01
  1144. begin scalar x;
  1145. if null (x := deleteall(nil,collectphystype args)) then
  1146. return nil
  1147. else if null cdr x then return car x
  1148. else rederr2('getphystypetimes,
  1149. list("PHYSOP type mismatch in",args))
  1150. end;
  1151. symbolic procedure multopop!*(u,v);
  1152. % u and v are physop exprs in a.e. form
  1153. % value is the product of u and v + commutators if needed
  1154. begin scalar x,y,u1,v1,stac!*,res;
  1155. % if there is no need for additional computations of commutators
  1156. % return the product as a standard quotient
  1157. u1:= physopaeval u;
  1158. v1:= physopaeval v;
  1159. if physopp u1 and physopp v1 then res := multopop(u1,v1)
  1160. else if physopp v1 then
  1161. if car u1 memq '(plus difference minus) then <<
  1162. x:= for each y in cdr u1 collect physoptimes list(y,v);
  1163. res:= reval3 (car u1 . x) >>
  1164. else if car u1 eq 'times then <<
  1165. stac!*:= reverse cdr u1; % begin with the last el
  1166. y:= v;
  1167. while stac!* do <<
  1168. x := car stac!*;
  1169. y := physoptimes list(x,y);
  1170. stac!* := cdr stac!*;
  1171. >>;
  1172. res:= y >>
  1173. else if car u1 eq 'quotient then res:= mk!*sq
  1174. quotsq(physop2sq physoptimes list(cadr u1,v),
  1175. physop2sq caddr u1)
  1176. else res:= physoptimes list(u1,v1)
  1177. else if car v1 memq '(plus difference minus) then <<
  1178. x:= for each y in cdr v1 collect physoptimes list(u,y);
  1179. res:= reval3 (car v1 . x) >>
  1180. else if car v1 eq 'times then <<
  1181. stac!*:= cdr v1;
  1182. y:= u;
  1183. while stac!* do <<
  1184. x := car stac!*;
  1185. y := physoptimes list(y,x);
  1186. stac!* := cdr stac!*;
  1187. % write "y= ",y," stac= ",stac!*;terpri();
  1188. >>;
  1189. res:= y >>
  1190. else if car v1 eq 'quotient then res:= mk!*sq
  1191. quotsq(physop2sq physoptimes list(u,cadr v1),
  1192. physop2sq caddr v1)
  1193. else res:= physoptimes list(u1,v1);
  1194. return res
  1195. end;
  1196. symbolic procedure multopop(u,v);
  1197. % u and v are physops (kernels)
  1198. % value is the product of physops + commutators if necessary
  1199. begin scalar res,x,ltype,rtype;
  1200. ltype := getphystype u;
  1201. rtype := getphystype v;
  1202. if ltype neq rtype then
  1203. rederr2('multopop,"type conflict in TIMES")
  1204. else if (invp u = v) then res := mk!*sq !*k2q 'unit
  1205. else if u = 'unit then res := mk!*sq !*k2q v
  1206. else if v = 'unit then res := mk!*sq !*k2q u
  1207. else if ordop(u,v) then
  1208. res := mk!*sq !*f2q multfnc(!*k2f u,!*k2f v)
  1209. else if noncommuting(u,v) then <<x:= comm2(u,v);
  1210. res:= if !*anticommchk then physopplus
  1211. list(list('minus,list('times,v,u)),x)
  1212. else physopplus
  1213. list(list('times,v,u),x) >>
  1214. else res := mk!*sq !*f2q multfnc(!*k2f v,!*k2f u);
  1215. return res
  1216. end;
  1217. physopfn('expt,'physopexpt);
  1218. symbolic procedure physopexpt args;
  1219. begin scalar n1,n2,lht,rht,lhtype,rhtype,x,y,z;
  1220. % we have to add a special bootstrap to avoid too much simplification
  1221. % in case of dot products raise to a power
  1222. lht := physopsm!* car args;
  1223. rht := physopsm!* cadr args;
  1224. lhtype := physopp lht ;
  1225. rhtype := physopp rht;
  1226. if rhtype then
  1227. rederr2('physopexpt,"operators in the exponent cannot be handled");
  1228. if not getphystype lht then lht := reval3 list('expt,lht,rht);
  1229. if not lhtype then
  1230. if numberp rht then <<
  1231. n1 := car divide(rht,2);
  1232. n2 := cdr divide(rht,2);
  1233. lhtype := getphystype lht;
  1234. if (lhtype and zerop rht) then lht := mk!*sq !*k2q 'unit %1.01
  1235. else if lhtype = 'vector then <<
  1236. x:= for k:= 1 : n1 collect physopdot list(lht,lht);
  1237. if onep n1 then x := 1 . x;
  1238. lht:= if zerop n2 then physoptimes x
  1239. else physoptimes append(x,list(lht));>>
  1240. else if lhtype = 'tensor then <<
  1241. x:= for k:= 1 : n1 collect physoptens list(lht,lht);
  1242. if onep n1 then x := 1 . x;
  1243. lht:= if zerop n2 then physoptimes x
  1244. else physoptimes append(x,list(lht));>>
  1245. else if lhtype = 'state then
  1246. rederr2('physopexpt,
  1247. "expressions involving states cannot be exponentiated")
  1248. else << lht := physopaeval lht;
  1249. x := deletemult!* collectindices lht;
  1250. z := lht;
  1251. for k :=2 :rht do <<
  1252. for each x1 in x do
  1253. if isavarindex x1 then
  1254. lht:= subst(makeanewvarindex(),x1,lht)
  1255. else lht:=subst(makeanewindex(),x1,lht);
  1256. y := append(y,list(lht));
  1257. lht := z; >>;
  1258. lht := physoptimes (z . y); >>;
  1259. >>
  1260. else lht := mk!*sq simpx1(physopaeval lht,physopaeval rht,1)
  1261. else if lht = 'unit then lht := mk!*sq !*k2q 'unit
  1262. else if numberp rht then lht := exptexpand(lht,rht)
  1263. else lht := mk!*sq !*P2q (lht . physopaeval rht); %0.99c
  1264. return lht
  1265. end;
  1266. put('expt,'phystypefn,'getphystypeexpt);
  1267. symbolic procedure getphystypeexpt args; % recoeded 0.99c
  1268. begin scalar x;
  1269. x := getphystypecar args;
  1270. return
  1271. if null x then nil
  1272. else if numberp cadr args and evenp cadr args then 'scalar
  1273. else x;
  1274. end;
  1275. symbolic procedure exptexpand(u,n);
  1276. begin scalar bool,x,y,v,n1,n2,res,flg;
  1277. if not numberp n then
  1278. rederr2('exptexpand,list("invalid argument ",n," to EXPT"));
  1279. if zerop n then return mk!*sq !*k2q 'unit; %1.01
  1280. bool := if n < 0 then t else nil;
  1281. n := if bool then abs(n) else n;
  1282. n1 := car divide(n,2);
  1283. n2 := cdr divide(n,2);
  1284. if zerop n1 then return mk!*sq !*k2q
  1285. if bool then invp u else u;
  1286. res := (1 . 1);
  1287. for k := 1 : n1 do <<
  1288. if scalopp u then
  1289. if bool then x := multf(!*k2f invp u, !*k2f invp u) . 1
  1290. else x := multf(!*k2f u, !*k2f u) . 1
  1291. % if bool then x:= list(list((invp u . 1),((invp u . 1) . 1))) . 1
  1292. % else x:= list(list((u . 1),((u . 1) . 1))) . 1
  1293. else if vecopp u then
  1294. if bool then x:= quotsq((1 . 1),physop2sq physopdot list(u,u))
  1295. else x:= physop2sq physopdot list(u,u)
  1296. else if tensopp u then <<
  1297. if bool then x:= quotsq((1 . 1),
  1298. physop2sq physoptens list(u,u))
  1299. else x:= physop2sq physoptens list(u,u) >>
  1300. else rederr2('exptexpand, "cannot raise a state to a power");
  1301. res := multsq(res,x)
  1302. >>;
  1303. b:
  1304. if zerop n2 then return mk!*sq res;
  1305. u:= if bool then invp u else u;
  1306. return mk!*sq multsq(res,!*k2q u)
  1307. end;
  1308. physopfn('quotient,'physopquotient);
  1309. symbolic procedure physopquotient args;
  1310. begin scalar lht, rht,y,lhtype,rhtype;
  1311. lht := physopsim!* car args;
  1312. rht := physopsim!* cadr args;
  1313. lhtype := getphystype car args;
  1314. rhtype := getphystype cadr args;
  1315. if rhtype memq '(vector state tensor) then
  1316. rederr2('physopquotient, "invalid quotient")
  1317. else if not rhtype then return
  1318. mk!*sq quotsq(physop2sq lht,physop2sq rht);
  1319. lhtype := physopp lht;
  1320. rht := physopaeval rht;
  1321. rhtype := physopp rht;
  1322. if rhtype then
  1323. if not lhtype then lht:= mk!*sq multsq(physop2sq lht,!*k2q invp rht)
  1324. else lht:= physoptimes list(lht,invp rht)
  1325. else if car rht eq 'times and null deadindices rht then
  1326. << rht := reverse cdr rht;
  1327. rht := for each x in rht collect
  1328. physopquotient list(1,x);
  1329. lht := physoptimes append(list(lht),rht) >>
  1330. else lht:= mk!*sq quotsq(physop2sq lht,physop2sq rht);
  1331. return lht
  1332. end;
  1333. put('quotient,'phystypefn,'getphystypeor);
  1334. physopfn('recip,'physoprecip);
  1335. symbolic procedure physoprecip args;
  1336. physopquotient list(1,args);
  1337. put('recip,'phystypefn,'getphystypecar);
  1338. symbolic procedure invphysop u;
  1339. % inverse of physops
  1340. begin scalar x,y;
  1341. if not physopp u then rederr2('invphysop,"invalid argument to INVERSE");
  1342. if u = 'unit then return u;
  1343. y:= if idp u then u else car u;
  1344. x := reversip explode y;
  1345. x := intern compress nconc(reversip x,list('!!,'!-,'!1));
  1346. put(y,'inverse,x); % 1.01
  1347. put(x,'inverse,y); % 1.01
  1348. put(x,'physopname,y); % 1.02
  1349. if not physopp x then << put(x,'rtype,'physop);
  1350. put(x,'phystype,get(y,'phystype));
  1351. put(x,'psimpfn,'physopsimp);
  1352. put(x,'tensdimen,get(y,'tensdimen));
  1353. physoplist!* := nconc(physoplist!*,list(x));
  1354. >>;
  1355. if idp u then return x
  1356. else return nconc(list(x),cdr u)
  1357. end;
  1358. symbolic procedure invp u; % recoded 1.01
  1359. % special cases
  1360. if u = 'unit then u
  1361. else if atom u then get(u,'inverse)
  1362. else if member(car u,'(comm anticomm)) then
  1363. list('quotient,1,u)
  1364. else get(car u,'inverse) . cdr u;
  1365. physopfn('sub,'physopsub); %subcommand;
  1366. % ********* redefinition of SUB handling is necessary in 3.4 **********
  1367. remprop('sub,'physopfunction);
  1368. put('sub,'physopfunction,'subeval);
  1369. put('physop,'subfn,'physopsub);
  1370. symbolic procedure physopsub(u,v); %redefined
  1371. % u is a list of substitutions as an a--list
  1372. % v is a simplified physop in prefix form
  1373. begin scalar res;
  1374. if null u or null v then return v;
  1375. v := physopaeval v;
  1376. for each x in u do v := subst(cdr x,car x,v);
  1377. return physopsm!* V
  1378. end;
  1379. % *********** end of 3.4 modifications ******************
  1380. symbolic procedure physopprog u;
  1381. % procedure to handle prog expressions (i.e. loops) containing physops
  1382. begin scalar x;
  1383. % we use basically the same trick as in physopsubs
  1384. % step 1: transform all physops on physoplist in normal ops
  1385. for each x in physoplist!* do <<remprop(x,'rtype);
  1386. put(x,'simpfn,'simpiden)>>;
  1387. % step 2: call normal prog on u
  1388. u := aeval ('prog . u);
  1389. % step 3: transform u back in an a.e.
  1390. u := physopaeval u;
  1391. % step 4: transform ops in physoplist back to physops
  1392. for each x in physoplist!* do <<remprop(x,'simpfn);
  1393. put(x,'rtype,'physop)>>;
  1394. % final step return u
  1395. return physopsm!* u
  1396. end;
  1397. % ****** procedures for physopfns ***********
  1398. physopfn('dot,'physopdot);
  1399. infix dot;
  1400. precedence dot,*;
  1401. symbolic procedure physopdot args;
  1402. begin scalar lht,rht,lhtype,rhtype,x,n,res;
  1403. lht := physopaeval physopsim!* car args;
  1404. rht := physopaeval physopsim!* cadr args;
  1405. lhtype := getphystype lht;
  1406. rhtype := getphystype rht;
  1407. if not( (lhtype and rhtype) and (lhtype eq 'vector) ) then
  1408. rederr2 ('physopdot,"invalid arguments to dotproduct");
  1409. lhtype := physopp lht;
  1410. rhtype := physopp rht;
  1411. if rhtype then
  1412. if lhtype then << if !*indflg then<<
  1413. lht := insertfreeindices(lht,nil);
  1414. rht := insertfreeindices(rht,nil);
  1415. indcnt!* := indcnt!* + 1; >>
  1416. else <<x := makeanewindex();
  1417. lht := insertindices(lht,x);
  1418. rht := insertindices(rht,x);>>;
  1419. res := physoptimes list(lht,rht)>>
  1420. else <<
  1421. if car lht eq 'minus then
  1422. res := mk!*sq negsq(physop2sq physopdot list(cadr lht,rht))
  1423. else if car lht eq 'difference then res := mk!*sq addsq(
  1424. physop2sq physopdot list(cadr lht,rht),negsq(physop2sq
  1425. physopdot list(caddr lht,rht)))
  1426. else if car lht eq 'plus then <<
  1427. x := for each y in cdr lht collect physopdot list(y,rht);
  1428. res := reval3 append(list('plus),x) >>
  1429. else if car lht eq 'quotient then <<
  1430. if not vecopp cadr lht then
  1431. rederr2('physopdot,"argument to DOT")
  1432. else res := mk!*sq quotsq(physop2sq
  1433. physopdot list(cadr lht,rht),physop2sq caddr lht) >>
  1434. else if car lht eq 'times then <<
  1435. for each y in cdr lht do
  1436. if getphystype y eq 'vector then x:=y;
  1437. lht :=delete(x,cdr lht);
  1438. res := physoptimes
  1439. nconc(lht,list(physopdot list(x,rht))) >>
  1440. else rederr2('physopdot, "invalid arguments to DOT") >>;
  1441. if not rhtype then <<
  1442. if car rht eq 'minus then
  1443. res := mk!*sq negsq(physop2sq physopdot list(lht,cadr rht))
  1444. else if car rht eq 'difference then res := mk!*sq addsq(
  1445. physop2sq physopdot list(lht,cadr rht),negsq(physop2sq
  1446. physopdot list(lht, caddr rht)))
  1447. else if car rht eq 'plus then <<
  1448. x := for each y in cdr rht collect physopdot list(lht,y);
  1449. res := reval3 append(list('plus),x) >>
  1450. else if car rht eq 'quotient then <<
  1451. if not vecopp cadr rht then
  1452. rederr2 ('physopdot,"invalid argument to DOT")
  1453. else res := mk!*sq quotsq(physop2sq physopdot
  1454. list(lht,cadr rht),physop2sq caddr rht) >>
  1455. else if car rht eq 'times then <<
  1456. for each y in cdr rht do if getphystype y eq 'vector then x:=y;
  1457. rht :=delete(x,cdr rht);
  1458. res := physoptimes
  1459. nconc(rht,list(physopdot list(lht,x))) >>
  1460. else rederr2 ('physopdot,"invalid arguments to DOT") >>;
  1461. return res
  1462. end;
  1463. put('dot,'phystype,'scalar);
  1464. symbolic procedure physoptens args;
  1465. % procedure for products of tensor expressions
  1466. begin scalar lht,rht,lhtype,rhtype,x,n,res;
  1467. lht := physopaeval physopsim!* car args;
  1468. rht := physopaeval physopsim!* cadr args;
  1469. lhtype := getphystype lht;
  1470. rhtype := getphystype rht;
  1471. if not( (lhtype and rhtype) and (lhtype eq 'tensor) ) then
  1472. rederr2 ('physoptens,"invalid arguments to tensproduct");
  1473. lhtype := physopp lht;
  1474. rhtype := physopp rht;
  1475. if rhtype then
  1476. if lhtype then << n:= get(lht,'tensdimen);
  1477. if (n neq get(rht,'tensdimen)) then
  1478. rederr2('physoptens,
  1479. "tensors must have the same dimension to be multiplied");
  1480. if !*indflg then<<
  1481. lht := insertfreeindices(lht,nil);
  1482. rht := insertfreeindices(rht,nil);
  1483. indcnt!* := indcnt!* + n; >>
  1484. else <<x := for k:= 1 : n collect makeanewindex();
  1485. lht := insertindices(lht,x);
  1486. rht := insertindices(rht,x);>>;
  1487. res := physoptimes list(lht,rht)>>
  1488. else <<
  1489. if car lht eq 'minus then
  1490. res := mk!*sq negsq(physop2sq physoptens list(cadr lht,rht))
  1491. else if car lht eq 'difference then res := mk!*sq addsq(
  1492. physop2sq physoptens list(cadr lht,rht),negsq(physop2sq
  1493. physoptens list(caddr lht,rht)))
  1494. else if car lht eq 'plus then <<
  1495. x := for each y in cdr lht collect physoptens list(y,rht);
  1496. res := reval3 append(list('plus),x) >>
  1497. else if car lht eq 'quotient then <<
  1498. if not tensopp cadr lht then
  1499. rederr2 ('physoptens,"invalid argument to TENS")
  1500. else res := mk!*sq quotsq(physop2sq
  1501. physoptens list(cadr lht,rht),physop2sq caddr lht) >>
  1502. else if car lht eq 'times then <<
  1503. for each y in cdr lht do
  1504. if getphystype y eq 'tensor then x:=y;
  1505. lht :=delete(x,cdr lht);
  1506. res := physoptimes
  1507. nconc(lht,list(physoptens list(x,rht))) >>
  1508. else rederr2('physoptens, "invalid arguments to TENS") >>;
  1509. if not rhtype then <<
  1510. if car rht eq 'minus then
  1511. res := mk!*sq negsq(physop2sq physoptens list(lht,cadr rht))
  1512. else if car rht eq 'difference then res := mk!*sq addsq(
  1513. physop2sq physoptens list(lht,cadr rht),negsq(physop2sq
  1514. physoptens list(lht, caddr rht)))
  1515. else if car rht eq 'plus then <<
  1516. x := for each y in cdr rht collect physoptens list(lht,y);
  1517. res := reval3 append(list('plus),x) >>
  1518. else if car rht eq 'quotient then <<
  1519. if not tensopp cadr rht then
  1520. rederr2 ('physoptens,"invalid argument to TENS")
  1521. else res := mk!*sq quotsq(physop2sq physoptens
  1522. list(lht,cadr rht),physop2sq caddr rht) >>
  1523. else if car rht eq 'times then <<
  1524. for each y in cdr rht do if getphystype y eq 'tensor then x:=y;
  1525. rht :=delete(x,cdr rht);
  1526. res := physoptimes
  1527. nconc(rht,list(physoptens list(lht,x))) >>
  1528. else rederr2('physoptens, "invalid arguments to TENS") >>;
  1529. return res
  1530. end;
  1531. put('tens,'phystype,'scalar);
  1532. % -------- procedures for commutator handling -------------
  1533. symbolic procedure comm2(u,v);
  1534. % general procedure for getting commutators
  1535. begin scalar x,utype,vtype,y,z,z1,res;
  1536. if not (physopp u and physopp v) then rederr2('comm2,
  1537. "invalid arguments to COMM");
  1538. utype := getphystype u;
  1539. vtype := getphystype v;
  1540. if not (utype eq 'scalar) and (vtype eq 'scalar) then
  1541. rederr2('comm2, "comm2 can only handle scalar operators");
  1542. !*anticommchk:= nil;
  1543. if not noncommuting(u,v) then return
  1544. if !*anticom then mk!*sq !*f2q multf(!*n2f 2,multfnc(!*k2f v,!*k2f u))
  1545. else mk!*sq (nil . 1);
  1546. x := list(u,v);
  1547. z := opmtch!* ('comm . x);
  1548. if null z then z:= if (y:= opmtch!* ('comm . reverse x)) then
  1549. physopsim!* list('minus,y)
  1550. else nil;
  1551. if z and null !*anticom then res:= physopsim!* z
  1552. else << z1 := opmtch!* ('anticomm . x);
  1553. if null z1 then
  1554. z1 := if (y:=opmtch!* ('anticomm . reverse x)) then y
  1555. else nil;
  1556. if z1 then << !*anticommchk := T;
  1557. res:= physopsim!* z1>>
  1558. >>;
  1559. if null res then
  1560. << !*hardstop:= T;
  1561. if null !*anticom then res := mk!*sq !*k2q ('comm . x)
  1562. else << !*anticommchk := T;
  1563. res := mk!*sq !*k2q ('anticomm . x) >>
  1564. >>;
  1565. return res
  1566. end;
  1567. physopfn('commute,'physopcommute);
  1568. symbolic procedure physopcommute args;
  1569. begin scalar lht,rht,lhtype,rhtype,x,n,res,flg;
  1570. lht := physopaeval physopsim!* car args;
  1571. rht := physopaeval physopsim!* cadr args;
  1572. lhtype := getphystype lht;
  1573. rhtype := getphystype rht;
  1574. if not (lhtype and rhtype) then return mk!*sq !*d2q 0
  1575. else if not(rhtype = lhtype) then
  1576. rederr2('physopcommute,
  1577. "physops of different types cannot be commuted")
  1578. else if not(lhtype eq 'scalar) then
  1579. rederr2 ('physopcommute,
  1580. "commutators only implemented for scalar physop expressions");
  1581. % flg := !*anticom; !*anticom := nil;
  1582. lhtype := physopp lht;
  1583. rhtype := physopp rht;
  1584. % write "lht= ",lht," rht= ",rht;terpri();
  1585. if rhtype then
  1586. if lhtype then << res := comm2(lht,rht);
  1587. if !*anticommchk then
  1588. res := physopdiff list(res,
  1589. physoptimes list(2,rht,lht)); >>
  1590. else res := mk!*sq negsq(physop2sq physopcommute list(rht,lht))
  1591. else <<
  1592. if car rht eq 'minus then res:= mk!*sq negsq(physop2sq
  1593. physopcommute list(lht, cadr rht));
  1594. if car rht eq 'difference then res := mk!*sq addsq(
  1595. physop2sq physopcommute list(lht,cadr rht),negsq(physop2sq
  1596. physopcommute list(lht,caddr rht)));
  1597. if car rht eq 'plus then <<
  1598. x:= for each y in cdr rht collect
  1599. physopcommute list(lht,y);
  1600. res:= reval3 append(list('plus),x) >>;
  1601. if car rht memq '(expt dot commute) then
  1602. res := physopcommute list(lht,physopsim!* rht);
  1603. if car rht eq 'quotient then
  1604. if physopp caddr rht then
  1605. res:= physopcommute list(lht,physopsim!* rht)
  1606. else
  1607. res := mk!*sq quotsq(physop2sq physopcommute list(lht,cadr rht),
  1608. physop2sq caddr rht);
  1609. if car rht eq 'times then <<
  1610. n := length cdr rht;
  1611. if (n = 2) then res := reval3 list('plus, physopsim!*
  1612. list('times,cadr rht,physopcommute list(lht, caddr rht)),
  1613. physopsim!* list('times,physopcommute list(lht, cadr rht),caddr rht))
  1614. else res := reval3 list('plus, physopsim!*
  1615. list('times,cadr rht,physopcommute list(lht,
  1616. append('(times),cddr rht))), physopsim!* append(
  1617. list('times,physopcommute list(lht, cadr rht)), cddr rht)) >>
  1618. >>;
  1619. % !*anticom := flg;
  1620. return res
  1621. end;
  1622. put('commute,'phystype,'scalar);
  1623. physopfn('anticommute,'physopanticommute);
  1624. symbolic procedure physopanticommute args;
  1625. begin scalar lht,rht,lhtype,rhtype,x,n,res,flg;
  1626. lht := physopaeval physopsim!* car args;
  1627. rht := physopaeval physopsim!* cadr args;
  1628. lhtype := getphystype lht;
  1629. rhtype := getphystype rht;
  1630. if not (lhtype and rhtype) then
  1631. return mk!*sq aeval list('plus,list('times,lht,rht),
  1632. list('times,rht,lht))
  1633. else if not(rhtype = lhtype) then
  1634. rederr2('physopanticommute,
  1635. "physops of different types cannot be commuted")
  1636. else if not(lhtype eq 'scalar) then
  1637. rederr2 ('physopanticommute,
  1638. "commutators only implemented for scalar physop expressions");
  1639. % flg := !*anticom;!*anticom :=t;
  1640. lhtype := physopp lht;
  1641. rhtype := physopp rht;
  1642. % write "lht= ",lht," rht= ",rht;terpri();
  1643. if rhtype then
  1644. if lhtype then
  1645. <<
  1646. x := comm2(lht,rht);
  1647. if null !*anticommchk then
  1648. If !*hardstop then res := mk!*sq !*k2q list('anticomm,lht,rht)
  1649. else res := reval3 list('plus,x,physoptimes list(2,rht,lht))
  1650. else res := x;
  1651. >>
  1652. else res := physopsim!* physopanticommute list(rht,lht)
  1653. else <<
  1654. if car rht eq 'minus then res:= mk!*sq negsq(physop2sq
  1655. physopanticommute list(lht, cadr rht));
  1656. if car rht eq 'difference then mk!*sq addsq(physop2sq
  1657. physopanticommute list(lht,cadr rht),negsq(physop2sq
  1658. physopanticommute list(lht,caddr rht)));
  1659. if car rht eq 'plus then <<
  1660. x:= for each y in cdr rht collect
  1661. physopanticommute list(lht,y);
  1662. res:= reval3 append(list('plus),x) >>
  1663. else res := physopplus list(physoptimes list(lht,rht),
  1664. physoptimes list(rht,lht));
  1665. >>;
  1666. % !*anticom := flg;
  1667. return res
  1668. end;
  1669. put('anticommute,'phystype,'scalar);
  1670. symbolic procedure commsimp u;
  1671. % procedure to simplify the arguments of COMM or ANTICOMM
  1672. % if they are not simple physops
  1673. begin scalar opname,x,y,flg,res;
  1674. opname := car u;
  1675. x := physopsim!* cadr u;
  1676. y := physopsim!* caddr u;
  1677. % write "op= ",opname," x= ",x," y= ",y;terpri();
  1678. flg := !*anticom;
  1679. if opname = 'anticomm then !*anticom := t;
  1680. res := if physopp x and physopp y then physopaeval comm2(x,y)
  1681. else if opname eq 'comm then list('commute,physopaeval x,
  1682. physopaeval y)
  1683. else list('anticommute,physopaeval x,physopaeval y);
  1684. !*anticom := flg;
  1685. return res
  1686. end;
  1687. % -------------- application of ops on states ----------------
  1688. physopfn('opapply,'physopapply);
  1689. infix opapply;
  1690. precedence opapply,-;
  1691. symbolic procedure physopapply args; % changed 0.99b
  1692. begin scalar lhtype,rhtype,wave,op,wavefct,res,x,y,flg;
  1693. lhtype := statep!* car args;
  1694. rhtype := statep!* cadr args;
  1695. if rhtype and lhtype then
  1696. return statemult(car args,cadr args)
  1697. else if rhtype then
  1698. <<wave := physopaeval physopsim!* cadr args;
  1699. op := physopaeval physopsim!* car args >>
  1700. else if lhtype then
  1701. <<wave := physopaeval physopadj list(car args);
  1702. op := physopaeval physopadj cdr args >>
  1703. % a previous application of physopapply may have annihilated the
  1704. % state
  1705. else if zerop car args or zerop cadr args then return mk!*sq (nil . 1)
  1706. else rederr2('opapply, "invalid arguments to opapply");
  1707. if null getphystype op then
  1708. res:= mk!*sq multsq(physop2sq op,physop2sq wave)
  1709. else if not physopp op then
  1710. if car op eq 'minus then
  1711. res := mk!*sq negsq(physop2sq physopapply list(cadr op,wave))
  1712. else if car op memq '(plus difference) then <<
  1713. for each y in cdr op do <<
  1714. res:= nconc(res,list(physopapply list(y,wave)));
  1715. if !*hardstop then flg:= t;
  1716. !*hardstop := nil;>>;
  1717. if flg then !*hardstop := t;
  1718. res := reval3 ((car op) . res) >>
  1719. else if car op memq '(dot commute anticommute expt) then
  1720. res := physopapply list(physopsim!* op,wave)
  1721. else if car op eq 'quotient then
  1722. if physopp caddr op then
  1723. res := physopapply list(physopsim!* op,wave)
  1724. else res := mk!*sq quotsq(physop2sq
  1725. physopapply list(cadr op,wave),physop2sq caddr op)
  1726. else if car op eq 'times then
  1727. <<op := reverse cdr op;
  1728. while op and not !*hardstop do
  1729. << x := car op; op := cdr op;
  1730. wave := physopapply list(x,wave) >>;
  1731. if !*hardstop then
  1732. if null op then res := wave
  1733. else << x:= physopaeval wave;
  1734. op := 'times . reverse op;
  1735. while x do
  1736. << y := car x; x := cdr x;
  1737. if listp y and
  1738. (y := assoc('opapply,y)) then
  1739. << wavefct := list('opapply,
  1740. nconc(op,list(cadr y)),
  1741. caddr y);
  1742. wave := subst(wavefct,y,wave);
  1743. >>;
  1744. >>;
  1745. res := wave;
  1746. >>
  1747. else res := wave;
  1748. >>
  1749. else rederr2('opapply, "invalid operator to opapply")
  1750. % special hack here for unit operator 0.99c
  1751. else if op = 'unit then res := mk!*sq physop2sq wave
  1752. else if physopp wave or
  1753. (flagp(car wave,'physopmapping) and statep!* cdr wave) then
  1754. <<x := opmtch!* list('opapply,op,wave);
  1755. if null x then x := physopadj list(
  1756. opmtch!* list('opapply,adjp wave,adjp op));
  1757. if null x then <<!*hardstop := t;
  1758. res := mk!*sq !*k2q
  1759. list('opapply,op,wave); >>
  1760. else res := mk!*sq physop2sq x;
  1761. >>
  1762. else << x := wave; wave := nil;
  1763. while x do <<
  1764. wavefct := car x; x := cdr x;
  1765. if statep!* wavefct then wave := nconc(wave,
  1766. list(physopaeval physopapply list(op,wavefct)))
  1767. else wave := nconc(wave,list(wavefct));
  1768. if !*hardstop then flg := t;
  1769. !*hardstop := nil >>;
  1770. if flg then !*hardstop := t;
  1771. res := mk!*sq physop2sq wave;
  1772. >>;
  1773. return res
  1774. end;
  1775. put('opapply,'phystypefn,'getphystypestate);
  1776. symbolic procedure getphystypestate args;
  1777. if statep!* car args and statep!* cadr args then nil
  1778. else 'state;
  1779. symbolic procedure statemult(u,v); % recoded 0.99c
  1780. % u and v are states
  1781. % returns product of these
  1782. begin scalar x,y,res,flg;
  1783. if not (statep!* u or statep!* v) then
  1784. rederr2 ('statemult,"invalid args to statemult");
  1785. if (not atom u and car v eq 'opapply) then
  1786. return expectval(u,cadr v,caddr v);
  1787. if (not atom u and car u eq 'opapply) then
  1788. return expectval(cadr u,caddr u,v);
  1789. u := physopaeval physopsim!* u;
  1790. v := physopaeval physopsim!* v;
  1791. if physopp u then
  1792. if physopp v then
  1793. <<
  1794. x := opmtch!* list('opapply,u,v);
  1795. if x then res := physop2sq aeval x
  1796. else
  1797. <<
  1798. x:= opmtch!* list('opapply,v,u);
  1799. if null x then
  1800. <<
  1801. !*hardstop := t;
  1802. res:= !*k2q list('opapply,u,v)
  1803. >>
  1804. else res := physop2sq aeval compconj x
  1805. >>;
  1806. >>
  1807. else
  1808. <<
  1809. x := deletemult!* !*collectphysops v;
  1810. for each y in x do
  1811. <<
  1812. v := subst(physopaeval statemult(u,y),y,v);
  1813. if !*hardstop then flg := t;
  1814. !*hardstop := nil;
  1815. >>;
  1816. if flg then !*hardstop := t;
  1817. res := physop2sq v;
  1818. >>
  1819. else
  1820. <<
  1821. x := deletemult!* !*collectphysops u;
  1822. for each y in x do
  1823. <<
  1824. u := subst(physopaeval statemult(y,v),y,u);
  1825. if !*hardstop then flg := t;
  1826. !*hardstop := nil;
  1827. >>;
  1828. if flg then !*hardstop := t;
  1829. res := physop2sq u;
  1830. >>;
  1831. return mk!*sq res
  1832. end;
  1833. symbolic procedure expectval(u,op,v);
  1834. % u and v are states
  1835. % calculates the expectation value < u ! op ! v >
  1836. % tries to apply op first on v, then on u
  1837. % PHYSOPAPPLY is used rather than STATEMULT to multiply
  1838. % resulting states together because of more general definition
  1839. begin scalar x,y,z,flg,res;
  1840. op := physopaeval physopsim!* op;
  1841. if null getphystype op then
  1842. return mk!*sq multsq(physop2sq op,physop2sq physopapply list(u,v));
  1843. if physopp op then
  1844. <<x := physopapply list(op,v);
  1845. if !*hardstop then
  1846. << !*hardstop := nil;
  1847. x:= physopapply list(u,op);
  1848. res := if !*hardstop then mk!*sq
  1849. !*k2q list('opapply,list('opapply,u,op),v)
  1850. else physopapply list(x,v) >>
  1851. else res:= physopapply list(u,x)
  1852. >>
  1853. else if car op eq 'minus then
  1854. res := mk!*sq negsq(physop2sq expectval(u,cadr op,v))
  1855. else if car op eq 'quotient then
  1856. if physopp caddr op then res := expectval(u,physopsm!* op,v)
  1857. else res := mk!*sq quotsq(physop2sq expectval(u,cadr op,v),
  1858. physop2sq caddr op)
  1859. else if car op memq '(dot commute anticommute expt) then
  1860. res := expectval (u,physopsm!* op,v)
  1861. else if car op memq '(plus difference) then
  1862. << for each y in cdr op do
  1863. << x:=nconc(x,list(expectval(u,y,v)));
  1864. if !*hardstop then flg:= !*hardstop ;
  1865. !*hardstop := nil >>;
  1866. if flg then !*hardstop := t;
  1867. res := reval3 ((car op) . x);
  1868. >>
  1869. else if car op eq 'times then
  1870. << x := physopapply list(op,v);
  1871. if not !*hardstop then return physopapply list(u,x);
  1872. x := cdr op;
  1873. while (x and !*hardstop and not flg) do
  1874. << y:=car x; x := cdr x;
  1875. if not getphystype y then << v:= physopapply list(y,v);
  1876. y := v;>>
  1877. else << !*hardstop := nil;
  1878. z:= physopapply list(u,y);
  1879. if !*hardstop then
  1880. << flg := T; x := y . x;
  1881. y := if null cdr x then list('opapply,car x,
  1882. physopaeval v)
  1883. else list('opapply,('times . x),
  1884. physopaeval v); >>
  1885. else << u:= z;
  1886. y:= if null x then v
  1887. else if null cdr x then
  1888. physopapply list(car x, physopaeval v)
  1889. else physopapply
  1890. list(('times . x),physopaeval v) >>
  1891. >>
  1892. >>;
  1893. res := if !*hardstop then mk!*sq !*k2q list('opapply,
  1894. physopaeval u,physopaeval y)
  1895. else physopapply list(u,y);
  1896. >>
  1897. else rederr2('expectval, "invalid args to expectval");
  1898. return res
  1899. end;
  1900. symbolic procedure compconj u;
  1901. % dirty and trivial implementation of
  1902. % complex conjugation of everything (hopefully);
  1903. % not yet tested for arrays
  1904. begin scalar x;
  1905. if null u or numberp u then return u
  1906. else if idp u and (x:=get(u,'rvalue)) then <<
  1907. x:=subst(list('minus,'I),'I,x);
  1908. put(u,'rvalue,x); return u >>
  1909. else return subst(list('minus,'I),'I,u)
  1910. end;
  1911. % -------------- adjoint of operators ---------------------
  1912. physopfn('adj, 'physopadj);
  1913. symbolic procedure physopadj arg;
  1914. begin scalar rht,rhtype,x,n,res;
  1915. rht := physopaeval physopsim!* car arg;
  1916. rhtype := physopp rht;
  1917. if rhtype then return mk!*sq !*k2q physopsm!* adjp rht
  1918. else <<
  1919. if not getphystype rht then res := aeval compconj rht
  1920. else if car rht eq 'minus then
  1921. res := mk!*sq negsq(physop2sq physopadj list(cadr rht))
  1922. else if car rht eq 'difference then res := mk!*sq addsq(
  1923. physop2sq physopadj list(cadr rht),negsq(physop2sq
  1924. physopadj list(caddr rht)))
  1925. else if car rht eq 'plus then <<
  1926. x := for each y in cdr rht collect physopadj list(y);
  1927. res := reval3 ('plus . x) >>
  1928. else if car rht eq 'quotient then <<
  1929. if not getphystype cadr rht then
  1930. rederr2('physopadj, "invalid argument to ADJ")
  1931. else res := mk!*sq quotsq(physop2sq
  1932. physopadj list(cadr rht),physop2sq caddr rht) >>
  1933. else if car rht eq 'times then <<
  1934. x:= for each y in cdr rht collect physopadj list(y);
  1935. res := physoptimes reverse x >>
  1936. else if flagp(car rht,'physopmapping) then
  1937. res := mk!*sq !*k2q list(car rht, physopaeval physopadj cdr rht)
  1938. else res :=physopadj list(physopsim!* rht) >>;
  1939. return res
  1940. end;
  1941. Put('adj,'phystypefn,'getphystypecar);
  1942. symbolic procedure adj2 u;
  1943. begin scalar x,y;
  1944. if not physopp u then rederr2('adj2, "invalid argument to adj2");
  1945. if u = 'unit then return u;
  1946. y:= if idp u then u else car u;
  1947. x := reverse explode y;
  1948. x := intern compress nconc(reverse x,list('!!,'!+));
  1949. put(y,'adjoint,x); %1.01
  1950. put(x,'adjoint,y); %1.01
  1951. put(x,'physopname,x); % 1.02
  1952. if not physopp x then << put(x,'rtype,'physop);
  1953. put(x,'phystype,get(y,'phystype));
  1954. put(x,'psimpfn,'physopsimp);
  1955. put(x,'tensdimen,get(y,'tensdimen));
  1956. defoporder!* := nconc(defoporder!*,list(x));
  1957. oporder!* := nconc(oporder!*,list(x));
  1958. physoplist!* := nconc(physoplist!*,list(x));
  1959. >>;
  1960. if idp u then return x
  1961. else return x . cdr u
  1962. end;
  1963. symbolic procedure invadj u; %new 1.01
  1964. % create the inverse adjoint op
  1965. begin scalar x,y;
  1966. if not physopp u then rederr2('invadj, "invalid argument to invadj");
  1967. if u = 'unit then return u;
  1968. y:= if idp u then u else car u;
  1969. x := reverse explode y;
  1970. x := intern compress nconc(reverse x,list('!!,'!+,'!!,'!-,'!1));
  1971. put(x,'adjoint,get(y,'inverse));
  1972. put(x,'inverse,get(y,'adjoint));
  1973. put(get(y,'inverse),'adjoint,x);
  1974. put(get(y,'adjoint),'inverse,x);
  1975. put(x,'physopname,get(y,'adjoint)); % 1.02
  1976. if not physopp x then << put(x,'rtype,'physop);
  1977. put(x,'phystype,get(y,'phystype));
  1978. put(x,'psimpfn,'physopsimp);
  1979. put(x,'tensdimen,get(y,'tensdimen));
  1980. physoplist!* := nconc(physoplist!*,list(x));
  1981. >>;
  1982. if idp u then return x
  1983. else return x . cdr u
  1984. end;
  1985. symbolic procedure adjp u; %recoded 1.01
  1986. % special cases
  1987. if u = 'unit then u
  1988. else if atom u then get(u,'adjoint)
  1989. else if (car u = 'comm) then
  1990. list('comm,adjp caddr u,adjp cadr u)
  1991. else if (car u = 'anticomm) then
  1992. list('anticomm,adjp cadr u,adjp caddr u)
  1993. else get(car u,'adjoint) . cdr u;
  1994. % --- end of arithmetic routines ---------------------
  1995. % ---- procedure for handling let assignements ------
  1996. symbolic procedure physoptypelet(u,v,ltype,b,rtype);
  1997. % modified version of original typelet
  1998. % General function for setting up rules for PHYSOP expressions.
  1999. % LTYPE is the type of the left hand side U, RTYPE, that of RHS V.
  2000. % B is a flag that is true if this is an update, nil for a removal.
  2001. % updated 101290 mw
  2002. %do not check physop type in prog exprs on the rhs
  2003. begin scalar x,y,n,u1,v1,z,contract;
  2004. if not physopp u and getphystype u then goto c; % physop expr
  2005. u1 := if atom u then u else car u;
  2006. if ltype then
  2007. if rtype = ltype then go to a
  2008. ELSE IF NULL B OR ZEROP V OR (LISTP V AND ((CAR V = 'PROG)
  2009. OR (CAR V = 'COND))) %1.01
  2010. or ((not atom u) and (car u = 'opapply)) then
  2011. return physopset(u,v,b)
  2012. else rederr2('physoptypelet,
  2013. list("physop type mismatch in assignement ",
  2014. u," := ",v))
  2015. else if null (x:= getphystype v) then return physopset(u,v,b)
  2016. else << if x = 'scalar then scalop u1;
  2017. if x = 'vector then vecop u1;
  2018. if x = 'state then state u1;
  2019. if x = 'tensor then tensop list(u1,get(v,'tensdimen));
  2020. ltype := rtype >>;
  2021. A: if b and (not atom u or flagp(u,'used!*)) then rmsubs();
  2022. % perform the assignement
  2023. physopset(u,v,b);
  2024. % phystype checking added 1.01
  2025. if b and (getphystype u neq getphystype v) then
  2026. rederr2('physoptypelet,
  2027. list("physop type mismatch in assignement ",
  2028. u," <=> ",v));
  2029. % special hack for commutators here
  2030. if (not atom u) and (car u = 'comm) then
  2031. physopset(list('comm,adjp caddr u,adjp cadr u),list('adj,v),b);
  2032. if (not atom u) and (car u = 'anticomm) then
  2033. physopset(list(car u,adjp cadr u,adjp caddr u),list('adj,v),b);
  2034. if null (x := getphystype u) or (x = 'state) or (x = 'scalar)
  2035. then return;
  2036. % we have here to add additional scalar let rules for vector
  2037. % and tensor operators with arbitrary indices
  2038. u1:=u;v1:=v;
  2039. if (x eq 'vector) or (x eq 'tensor) then
  2040. << x := collectphysops u;
  2041. for each z in x do
  2042. u1:= subst(insertfreeindices(z,nil),z,u1);
  2043. x := collectphysops v;
  2044. for each z in x do
  2045. v1:= subst(insertfreeindices(z,nil),z,v1) >>;
  2046. physoptypelet(u1,v1,ltype,b,rtype);
  2047. return;
  2048. C:
  2049. % this is for more complicated let rules involving more than
  2050. % one term on the lhs
  2051. % special hack here to handle let rules involving elementary
  2052. % OPAPPLY relations
  2053. if car u = 'opapply then return physopset(u,v,b);
  2054. % step 1: do all physop simplifications on lhs
  2055. % we set indflg!* for dot product simplifications on the lhs
  2056. !*indflg:= T; indcnt!* := 0;
  2057. contract := !*contract2; !*contract2 := T;
  2058. u := physopsm!* u;
  2059. !*indflg := nil; indcnt!* := 0; !*contract2 := contract;
  2060. % check correct phystype
  2061. x := getphystype u;
  2062. y := getphystype v;
  2063. if b and ((not (y or zerop v)) or (y and (x neq y))) then
  2064. rederr2 ('physoptypelet,"phystype mismatch in LET");
  2065. % step 2 : transform back in ae
  2066. u := physopaeval u;
  2067. % write "u= ",u; terpri();
  2068. % ab hier neu
  2069. % step3 : do some modifications in case of a sum or difference on the lh
  2070. if car u = 'PLUS then
  2071. <<
  2072. u1 := cddr u;
  2073. u := cadr u;
  2074. v := list('plus,v);
  2075. for each x in u1 do
  2076. <<
  2077. x := list('minus,x);
  2078. v := append(v,list(x));
  2079. >>;
  2080. >>;
  2081. if car u = 'DIFFERENCE then
  2082. <<
  2083. u1:= cddr u;
  2084. u:= cadr u;
  2085. v := append(list('plus,v),list(u1));
  2086. >>;
  2087. if car U = 'MINUS then
  2088. <<
  2089. u := cadr u;
  2090. v := list('minus,v);
  2091. >>;
  2092. % step 4: add the rule to the corresponding list
  2093. % expression may still contain quotients and expt
  2094. if car u ='EXPT then
  2095. <<
  2096. u := cadr u . caddr u;
  2097. powlis1!* := xadd!*(u .
  2098. list(nil . (if mcond!* then mcond!* else t),
  2099. v,nil), powlis1!*,b)
  2100. >>
  2101. else if car u = 'quotient then
  2102. <<
  2103. v:= list('times,v,caddr u);
  2104. physoptypelet(cadr u,v,ltype,b,rtype);
  2105. >>
  2106. else % car u = times
  2107. <<
  2108. u1 := nil;
  2109. for each x in cdr u do
  2110. <<
  2111. if car x= 'expt then
  2112. u1 := append(u1,list(cadr x . caddr x))
  2113. else if car x = 'quotient then
  2114. <<
  2115. v:= list('times,v,caddr x);
  2116. u1 := append(u1,
  2117. list(if cadr x = 'expt then
  2118. (caddr x . cadddr x)
  2119. else (cadr x . 1)));
  2120. >>
  2121. else u1 := append(u1,list(x . 1));
  2122. >>;
  2123. !*match := xadd!*(u1 . list(nil .
  2124. (if mcond!* then mcond!* else t),
  2125. v,nil), !*match,b);
  2126. >>;
  2127. return;
  2128. end;
  2129. symbolic procedure physopset(u,v,b);
  2130. % assignement procedure for physops
  2131. % special hack for assignement of unresolved physop expressions
  2132. begin
  2133. if not atom u then put(car u,'opmtch,xadd!*(cdr u .
  2134. list(nil . (if mcond!* then mcond!* else t),
  2135. v,nil), get(car u,'opmtch),b))
  2136. else if b then
  2137. if physopp u then put(u,'rvalue,physopsim!* v)
  2138. else put(u,'avalue,list('scalar,
  2139. list('!*sq,cadr physopsim!* v,not !*hardstop)))
  2140. else if not member(u,specoplist!*) then
  2141. << remprop(u,'rvalue);
  2142. remprop(u,'opmtch);
  2143. >>;
  2144. !*hardstop := nil;
  2145. end;
  2146. symbolic procedure clearphysop u;
  2147. % to remove physop type from an id
  2148. begin scalar y;
  2149. for each x in u do <<
  2150. if not (physopp x and idp x) then rederr2('clearphysop,
  2151. list("invalid argument ",x," to CLEARPHYSOP"));
  2152. y := invp x;
  2153. remprop(y,'rtype);
  2154. remprop(y,'tensdimen);
  2155. remprop(y,'phystype);
  2156. remprop(y,'psimpfn);
  2157. remprop(y,'inverse); %1.01
  2158. remprop(y,'adjoint); %1.01
  2159. remprop(y,'rvalue); % 1.01
  2160. oporder!* := delete(y,oporder!*);
  2161. defoporder!* := delete(y,defoporder!*);
  2162. physoplist!* := delete(y,physoplist!*);
  2163. y:= adjp x;
  2164. remprop(y,'rtype);
  2165. remprop(y,'tensdimen);
  2166. remprop(y,'phystype);
  2167. remprop(y,'psimpfn);
  2168. remprop(y,'inverse); %1.01
  2169. remprop(y,'adjoint); %1.01
  2170. remprop(y,'rvalue); % 1.01
  2171. oporder!* := delete(y,oporder!*);
  2172. defoporder!* := delete(y,defoporder!*);
  2173. physoplist!* := delete(y,physoplist!*);
  2174. remprop(x,'rtype);
  2175. remprop(x,'tensdimen);
  2176. remprop(x,'phystype);
  2177. remprop(x,'psimpfn);
  2178. remprop(x,'inverse); %1.01
  2179. remprop(x,'adjoint); %1.01
  2180. remprop(x,'rvalue); % 1.01
  2181. oporder!* := delete(x,oporder!*);
  2182. defoporder!* := delete(x,defoporder!*);
  2183. physoplist!* := delete(x,physoplist!*);
  2184. >>;
  2185. return nil
  2186. end;
  2187. Rlistat '(clearphysop);
  2188. %------ procedures for printing out physops correctly ---------
  2189. % we modify the standard MAPRINT routine to get control
  2190. % over the printing of PHYSOPs
  2191. %**** This section had to be modified for 3.4 **********************
  2192. symbolic procedure physoppri u; % modified 3.4
  2193. begin scalar x,y,z,x1;
  2194. x := if idp u then u else car u;
  2195. y := if idp u then nil else cdr u;
  2196. trwrite(physoppri,"x= ",x," y= ",y,"nat= ",!*nat," contract= ",
  2197. !*contract);
  2198. if !*nat and not !*contract then go to a;
  2199. % transform the physop name in a string in order not to loose the
  2200. % special characters
  2201. x:= compress append('!" . explode x,list('!"));
  2202. prin2!* x;
  2203. if y then << prin2!* "(";
  2204. obrkp!* := nil;
  2205. inprint('!*comma!*,0,y);
  2206. obrkp!* := t;
  2207. prin2!* ")" >>;
  2208. return u;
  2209. a:
  2210. x := reverse explode x;
  2211. if length(x) > 2 then
  2212. if cadr x = '!- then <<z := compress list('!-,'!1);
  2213. x := compress reverse pnth(x,4); >>
  2214. else if car x = '!+ then << z:='!+;
  2215. x:= compress reverse pnth(x,3); >>
  2216. else x := compress reverse x
  2217. else x := compress reverse x;
  2218. x:= compress append('!" . explode x,list('!"));
  2219. x1 := if y then x . y else x;
  2220. trwrite(physoppri,"x= ",x," z= ",z," x1= ",x1);
  2221. % if z then exptpri(get('expt,'infix),list(x1,z))
  2222. % the following is 3.4
  2223. if z then exptpri(list('expt,x1,z),get('expt,'infix))
  2224. else << prin2!* x;
  2225. if y then << prin2!* "(";
  2226. obrkp!* := nil;
  2227. inprint('!*comma!*,0,y);
  2228. obrkp!* := t;
  2229. prin2!* ")" >>
  2230. >>;
  2231. return u
  2232. end;
  2233. symbolic procedure maprint(l,p!*!*); %3.4 version
  2234. begin scalar p,x,y;
  2235. p := p!*!*; % p!*!* needed for (expt a (quotient ...)) case.
  2236. if null l then return nil
  2237. else if physopp l then return apply1('physoppri,l)
  2238. else if atom l
  2239. then <<if not numberp l or (not(l<0) or p<=get('minus,'infix))
  2240. then prin2!* l
  2241. else <<prin2!* "("; prin2!* l; prin2!* ")">>;
  2242. return l >>
  2243. else if stringp l then return prin2!* l
  2244. else if not atom car l then maprint(car l,p)
  2245. else if ((x := get(car l,'pprifn)) and
  2246. not(apply2(x,l,p) eq 'failed)) or
  2247. ((x := get(car l,'prifn)) and
  2248. not(apply1(x,l) eq 'failed))
  2249. then return l
  2250. else if x := get(car l,'infix) then <<
  2251. p := not(x>p);
  2252. if p then <<
  2253. y := orig!*;
  2254. prin2!* "(";
  2255. orig!* := if posn!*<18 then posn!* else orig!*+3 >>;
  2256. % (expt a b) was dealt with using a pprifn sometime earlier than this
  2257. inprint(car l,x,cdr l);
  2258. if p then <<
  2259. prin2!* ")";
  2260. orig!* := y >>;
  2261. return l >>
  2262. else prin2!* car l;
  2263. prin2!* "(";
  2264. obrkp!* := nil;
  2265. y := orig!*;
  2266. orig!* := if posn!*<18 then posn!* else orig!*+3;
  2267. if cdr l then inprint('!*comma!*,0,cdr l);
  2268. obrkp!* := t;
  2269. orig!* := y;
  2270. prin2!* ")";
  2271. return l
  2272. end;
  2273. % ******* end of 3.4 modifications ********************
  2274. % ------- end of module printout -------------------------
  2275. % ------------- some default declarations -------------------
  2276. % this list contains operators which when appearing in expressions
  2277. % have unknown properties (unresolved expressions)
  2278. specoplist!* := list('dot,'comm,'anticomm,'opapply);
  2279. % unit,comm and anticomm operators
  2280. put('comm,'rtype,'physop);
  2281. put('comm,'phystype,'scalar);
  2282. put('comm,'psimpfn,'commsimp);
  2283. put('anticomm,'rtype,'physop);
  2284. put('anticomm,'phystype,'scalar);
  2285. put('anticomm,'psimpfn,'commsimp);
  2286. physoplist!* := list('comm,'anticomm);
  2287. scalop 'unit;
  2288. flag ('(unit comm anticomm opapply),'reserved);
  2289. endmodule;
  2290. end;