physop.red 86 KB

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