contrtns.red 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. module contrtns;
  2. global '(dimex!* sgn!* signat!* spaces!* numindxl!* pair_id_num!*) ;
  3. lisp (pair_id_num!*:= '((!0 . 0) (!1 . 1) (!2 . 2) (!3 . 3) (!4 . 4)
  4. (!5 . 5) (!6 . 6) (!7 . 7) (!8 . 8) (!9 . 9)
  5. (!10 . 10) (!11 . 11) (!12 . 12) (!13 . 13)));
  6. fluid('(dummy_id!* g_dvnames epsilon!* !*distribute));
  7. % g_dvnames is a vector.
  8. switch onespace;
  9. !*onespace:=t; % working inside a unique space is the default.
  10. fluid('(indxl_tens!* dummy_id!* g_dvnames)); % g_dvnames is a vector.
  11. % This module contains the procedures which enhances the
  12. % capabilities of 'canonical' which is the master function of DUMMY.RED.
  13. % That function is now able to make tensor-like expressions contractions
  14. % and to find the normal form of an expression containing "tensors"
  15. % and derivatives of these and of operators.
  16. % auxiliary functions to canonical:
  17. symbolic procedure no_dum_varp u;
  18. % u is the mvar of a msf
  19. % returns t if the indices are all variables or if
  20. % no indices.
  21. % this is a variation on 'nodum_varp' which should still
  22. % be improved.
  23. if null cdr u or (splitlist!:(cdr u,'list)=cdr u) then t
  24. else nil;
  25. %symbolic procedure no_dum_varp u;
  26. % u is the mvar of a msf
  27. % returns t if the indices are all variables
  28. % or if
  29. % covariant and contravariant indices are the same.
  30. % this is a variation on 'nodum_varp' which should still
  31. % be improved.
  32. % it was aimed to avoid elimination of powers for traces but
  33. % it does not work because they are treated as operators
  34. % in sep-tens_from_other
  35. % if null cdr u or (splitlist!:(cdr u,'list)=cdr u) then t
  36. % else
  37. % begin scalar ll;
  38. % ll:= splitlist!:(cdr u,'list);
  39. % if ll then
  40. % <<ll:=car ll;
  41. % ll:= for each y in split_cov_cont_ids cdr u collect ordn delete(ll,y)>>
  42. % else
  43. % ll:=for each y in split_cov_cont_ids cdr u collect ordn y;
  44. % if car ll = cadr ll then return t
  45. % end;
  46. symbolic procedure sep_tens_from_other u;
  47. % u is a standard form which describes a monomial.
  48. % output is list(<ordered list of tensor kernels>,<standard form without tensors>)
  49. % does NOT change ordering since multiplication is not necessarily
  50. % commutative.
  51. begin scalar mv,tel,other,y;
  52. other:= !*n2f 1;
  53. l: if numberp u then return list(reversip tel, multf(other,!*n2f u))
  54. else
  55. if atom mvar u then other:=multf(other,!*p2f lpow u)
  56. else
  57. << if y:=get(car mvar u, 'Translate1) then
  58. << u:=fullcopy u; (mvar u:= apply1(y,mvar u)) >>;
  59. % if tensorp mvar u then tel:=mvar u . tel
  60. % else other :=multf(other,!*p2f lpow u)>>;
  61. if tensorp(mv:=mvar u) then
  62. if null no_dum_varp mv
  63. or flagp(car mv,'noncom) then tel:=mvar u . tel
  64. else other :=multf(other,!*p2f lpow u)
  65. else other :=multf(other,!*p2f lpow u)
  66. >>;
  67. u:= lc u;
  68. go to l;
  69. end;
  70. symbolic procedure all_index_lst u;
  71. % u is a list of tensor kernels.
  72. % output is the list of all indices
  73. % example:
  74. % cc:= car sep_tens_from_other bb;
  75. % ((te r b (minus c)) (te r (minus s) (minus d)) (te (minus r) c d))
  76. % gives (r b (minus c) r (minus s) (minus d) (minus r) c d)
  77. if null u then nil
  78. else append(
  79. ((if listp car y and caar y = 'list then cdr y
  80. else y ) where y=cdar u),
  81. all_index_lst cdr u);
  82. symbolic procedure del_affin_tens u;
  83. % u is a list of tensor kernels
  84. if null u then nil
  85. else
  86. if affinep car u then del_affin_tens cdr u
  87. else car u . del_affin_tens cdr u;
  88. symbolic procedure dv_canon_covcont(sf);
  89. % for Riemanian spaces, places contravariant dummy indices first
  90. % in place.
  91. if domainp sf then sf
  92. else
  93. begin scalar tenslist,idlist,dummyid;
  94. dummyid:=dummy_id!*;
  95. tenslist:=car sep_tens_from_other(sf); % get tensor list;
  96. % y:=del_affin_tens y;
  97. if null tenslist then return restorealldfs sf;
  98. idlist:=all_index_lst tenslist; %get list of all indexes;
  99. for each z in tenslist do
  100. if (get(car z,'partic_tens)='simpdel) or affinep z then
  101. for each y in cdr z do
  102. dummyid:=delete(raiseind!: y, dummyid);
  103. for each z in idlist do
  104. if atom z then
  105. (if z memq dummyid
  106. % first dummy index is high. no more to do with it.
  107. then dummyid:=delete(z,dummyid))
  108. else if careq_minus z and memq(cadr z,dummyid) then
  109. % first dummy index is low, change this.
  110. << sf:=subst(list('minus,cadr z),cadr z,sf);
  111. dummyid:=delete(cadr z,dummyid)>>;
  112. return restorealldfs sf;
  113. end;
  114. symbolic procedure cov_contp(u,v);
  115. % u and v are lists of tensors indices
  116. % verify if one has expressions of the form
  117. % (a,b,c,...) and ((minus a')(minus b')(minus c')...)
  118. % for u and v or for v and u.
  119. % IMPORTANT for epsilon products.
  120. cov_lst_idsp u and cont_lst_idsp v
  121. or cont_lst_idsp u and cov_lst_idsp v;
  122. symbolic procedure belong_to_spacep(u,sp);
  123. % u is a list of indices
  124. % sp is the name of a space
  125. % t if ALL INDICES belong to sp.
  126. % I do not think it is still needed. ****
  127. if null u or sp = 'wholespace then t
  128. else
  129. if get(car u,'space) eq sp then belong_to_spacep (cdr u,sp);
  130. symbolic procedure extract_tens(tel,sp_tens);
  131. % tel is a list of tensor kernels as given by the car of the
  132. % output of 'sep_tens_from_other'
  133. % sp_tens is the name of a special tensor
  134. % result is a list of these tensors found in tel
  135. if null tel then nil
  136. else
  137. if caar tel = sp_tens then
  138. car tel . extract_tens(cdr tel,sp_tens)
  139. else extract_tens(cdr tel,sp_tens);
  140. symbolic procedure treat_dummy_ids(sf);
  141. % manage all dummy indices by interfacing with dummy.red
  142. % Creates bags of ids belonging to same space, and them call
  143. % the simplification procedure form dummy.
  144. if !*onespace
  145. then
  146. begin scalar user_g_dvnames,res;
  147. user_g_dvnames:=g_dvnames;
  148. dummy_nam dummy_id!*;
  149. res:=dv_canon_monomial sf;
  150. g_dvnames:=user_g_dvnames;
  151. return if g_dvnames then dv_canon_covcont dv_canon_monomial res
  152. else dv_canon_covcont res;
  153. end
  154. else
  155. begin scalar res,partit_space_lst,idxl,sp,user_g_dvnames,bool;
  156. partit_space_lst:=nil;
  157. user_g_dvnames:=g_dvnames;
  158. partit_space_lst:=for each y in spaces!* collect car y . nil;
  159. % Put each index with the ones belonging to same space
  160. for each z in dummy_id!* do
  161. if sp:=space_of_idx z then
  162. % dummy indices which have not been declared to belong to a (sub)space
  163. % are assumed to belong to 'wholespace'
  164. % and no error statement is generated iff 'wholespace' has been defined.
  165. if idxl:=assoc(sp,partit_space_lst) then
  166. cdr idxl:= z . cdr idxl
  167. else rerror(cantens,14,
  168. list("Index ",z," does not belong to a defined space"));
  169. res:=sf;
  170. for each z in partit_space_lst do
  171. if (idxl:=cdr z)
  172. then <<bool:=t; dummy_nam idxl;
  173. res:=dv_canon_monomial(res)>>;
  174. if not bool then res:=dv_canon_monomial res; %% added
  175. g_dvnames:=user_g_dvnames;
  176. return if g_dvnames then dv_canon_covcont dv_canon_monomial res
  177. else dv_canon_covcont res;
  178. end;
  179. %
  180. % the dummy user procedure modified to perform tens calculations
  181. %
  182. symbolic procedure canonical sq;
  183. begin scalar sf, denom, !*distribute;
  184. sq := simp!* car sq;
  185. denom := denr sq;
  186. on distribute;
  187. sf := distri_pol numr sq;
  188. % Check coherence of dummy and free indices and generate dummy_id!*..
  189. %% simplify the whole thing, and return
  190. return simp!*( {'!*sq,
  191. canonical1(sf, cadr check_ids(sf)) ./ denom, nil} );
  192. end;
  193. symbolic procedure canonical1 (sf, dumlist);
  194. begin scalar dummy_id!*, res;
  195. dummy_id!*:=dumlist;
  196. % WE MUST BE SURE THAT FURTHER SIMPLIFICATIONS WILL
  197. % NOT REPLACE AN ST BY SEVERAL ST's
  198. % IF RULES ARE APPLIED THEY SHOULD HAVE ACTED BY NOW.
  199. % IF SEVERAL TENSORS ARE OF THE EPSI KIND THEY MUST ANALYZED
  200. % AND, POSSIBLY, REPLACED BY 'DEL' OR EXPANSIONS OF IT.
  201. % FOR INSTANCE e(-a,-b)*e(c,d)=
  202. % del(-a,c)*delt(-b,d) - del(-a,d)*delt(-b,c)
  203. % then we must generate a SUM of standard forms
  204. % This is HERE that products of epsilon tensors should be dealt with
  205. % => SIMPEPSE.RED.
  206. % Epsi simplification.
  207. while not domainp sf do
  208. << res:=addf(res,simpepsi_mon_expr(lt sf .+ nil));
  209. sf:=red sf;
  210. >>;
  211. sf:= distri_pol addf(res,sf);
  212. res:=nil;
  213. while not domainp(sf) do
  214. <<
  215. (if length car y >=2
  216. then res:= addf(res,dv_canon_tensor y)
  217. else res := addf(res, treat_dummy_ids(lt sf .+ nil)))
  218. where y=sep_tens_from_other (lt sf .+ nil);
  219. sf:=red sf;
  220. >>;
  221. clearallnewids();
  222. % Now add the domainp term:
  223. return
  224. res := addf(res,sf);
  225. end;
  226. symbolic procedure tensor_has_dummy_idx(dum,te);
  227. % dum is a list of dummy indices
  228. % te is a tensor in prefix form.
  229. % T(rue) if one of the indices of te belongs to dum.
  230. if null dum then nil
  231. else
  232. if smember(car dum, te) then t
  233. else tensor_has_dummy_idx(cdr dum,te);
  234. symbolic procedure tens_list_is_generic tel;
  235. % tel is a list of tensors
  236. % output is T(rue) if ALL tensors are generic
  237. if null tel then t else
  238. if null get(caar tel,'partic_tens) then tens_list_is_generic cdr tel;
  239. symbolic procedure mk_delta_first tel;
  240. % input is a list of tensor kernels.
  241. % output is an equivalent list with
  242. % all delta-like tensors placed first
  243. % and eta-like tensors second.
  244. begin scalar x,y,z;
  245. x:=extract_tens(tel,get('delta,'name));
  246. z:=setdiff(tel,x);
  247. y:=extract_tens(z,get('eta,'name));
  248. z:=setdiff(z,y);
  249. return append(x,append(y,z))
  250. end;
  251. symbolic procedure dv_canon_tensor u;
  252. % u is list(<list of tensor kernels>,<standard form without tensors>)
  253. % output is a standard form given to dv_canon_monomial.
  254. % First take the list of tensor kernels and make the contractions
  255. % if necessary.
  256. begin scalar x,tel,tel_dum,tel_free,notens;
  257. tel:=car u; tel_free:=!*n2f 1; notens:=cadr u;
  258. % replace the list tel by tel_dum
  259. % where tel_dum contains tensors with dummy indices.
  260. % and put the rest in tel_free
  261. for each y in tel do
  262. if tensor_has_dummy_idx(dummy_id!*,y) then tel_dum:=y . tel_dum
  263. else tel_free:=multf(!*k2f y,tel_free);
  264. tel_dum:=tel_dum; % to restitute the order
  265. % now tel_dum must eventually be transformed by contractions.
  266. % Two cases appear:
  267. % all tensors in tel_dum are generic:
  268. return
  269. if tens_list_is_generic tel_dum then
  270. <<x:=!*n2f 1;
  271. if tel_dum then tel_dum:=for each y in tel_dum collect !*k2f y;
  272. while tel_dum do <<
  273. x:=multf(car tel_dum, x);tel_dum:=cdr tel_dum;
  274. >>;
  275. multf(restorealldfs tel_free,treat_dummy_ids multf(x,notens))
  276. >>
  277. % one or several tensors are particular ones:
  278. else
  279. % simptensexpr must output a standard form.
  280. multf(restorealldfs tel_free,
  281. treat_dummy_ids multf(simptensexpr(
  282. mk_delta_first tel_dum,dummy_id!*,1),notens));
  283. end;
  284. symbolic procedure simptensexpr(tel,dum,i);
  285. % tel is the list of tensor kernels
  286. % dum is the associated list of dummy variable
  287. % output should be the standard form of the contracted tensors.
  288. begin scalar res;
  289. res:=!*n2f 1;
  290. return
  291. if numberp tel then !*n2f tel
  292. else
  293. if atom tel or length tel=1 then !*k2f car tel
  294. else
  295. if i>=length tel + 1 then
  296. <<for each i in tel do res:=multf(res,!*k2f i);res>>
  297. else
  298. (if y memq list('simpdelt,'simpeta,'simpmetric)
  299. then simpdeltetaexpr(tel,dum,i)
  300. else simptensexpr(tel,dum,i+1)
  301. % here the epsi tensors should NOT be considered
  302. % since they are already simplified.
  303. )where y=get(car nth(tel,i),'partic_tens);
  304. end;
  305. symbolic procedure simpdeltetaexpr(tel,dum,i);
  306. % output is the result of contraction of the ith tensor
  307. % with the other ones.
  308. % tensor with the other-ones (at least one is present).
  309. % The SAME procedure appears to be valid for BOTH 'delta' and 'eta'.
  310. begin scalar itel,rtel,res,old,new;
  311. % itel is delta tensor kernel.
  312. % rtel is the list of the other tensors
  313. % res is the new list of kernels.
  314. itel:=nth(tel,i);
  315. if (id_switch_variance cadr itel) neq caddr itel
  316. and intersection(flatindxl cdr itel,dum) then
  317. << rtel:=remove(tel,i);
  318. % let us identify where the dummy index in itel is:
  319. % and define substitution variables:
  320. if (old:=raiseind!: cadr itel) memq dum
  321. then << old:=id_switch_variance cadr itel; new:=caddr itel >>
  322. else << old:=id_switch_variance caddr itel; new:=cadr itel >>;
  323. res:=subst(new,old,rtel);
  324. return simptensexpr(res,dum,i)
  325. >>
  326. else return simptensexpr(tel,dum,i+1);
  327. end;
  328. symbolic procedure select_epsi_pairs ep;
  329. % result is a list of PAIRS of contractible (to DEL)
  330. % epsilon-pairs.
  331. % if there are 3 or more epsilons of a given kind,
  332. % they are eliminated. So contractions will NOT be done.
  333. % to allow for this, generalize THIS procedure.
  334. % the problem however is which two among the three of
  335. % should we choose.
  336. if null ep then nil
  337. else
  338. (if length x = 2 and cov_contp(cdar x,cdadr x) then
  339. x . select_epsi_pairs cdr ep
  340. else select_epsi_pairs cdr ep) where x=car ep;
  341. symbolic procedure mk_eps_lst tkl;
  342. % tkl is a list of tensor kernels
  343. % extract the list of contractible epsilon pairs from tkl
  344. % and substracts them from tkl.
  345. % returns list(<epsilon pair list>,<new tkl>) or nil.
  346. begin scalar eps_lst;
  347. eps_lst:= if !*onespace and get('epsilon,'name) then
  348. list extract_tens(tkl,find_name('epsilon))
  349. else
  350. if epsilon!* then
  351. for each i in epsilon!* collect extract_tens(tkl,car i)
  352. else nil;
  353. eps_lst:=select_epsi_pairs eps_lst;
  354. if null eps_lst then
  355. return list(nil,tkl);
  356. for each j in eps_lst do tkl:=setdiff(tkl,j);
  357. return list(eps_lst,tkl)
  358. end;
  359. symbolic procedure get_sign_space!: u;
  360. if null u then signature '? else
  361. get_sign_space u;
  362. symbolic procedure epsi_to_del(ep);
  363. % ep is a list of contractible epsilon pairs.
  364. % returns a standard form which represents the product of
  365. % the DEL-like objects
  366. % First task: replace all eps-products by DEL-like objects
  367. % taking properly into account the space signature.
  368. % Second task: reconstruct the SF-product.
  369. if null ep then nil
  370. else
  371. begin scalar del_prd,x,y;
  372. % del_prd is the SF which results from application of SIMPDEL
  373. del_prd:=!*n2f 1;
  374. for each j in ep do
  375. <<x:=all_index_lst j;
  376. if get_sign_space!:(if y:=assoc(caar j,epsilon!*) then cdr y
  377. else nil) = 1 then
  378. del_prd:=multf(negf apply1('simpdel,find_name('del) . x), del_prd)
  379. else del_prd:=multf(apply1('simpdel,find_name('del) . x), del_prd)>>;
  380. return del_prd
  381. end;
  382. symbolic procedure simpepsi_mon_expr msf;
  383. % msf is a monomial standard form.
  384. % result is a NEW STANDARD FORM after simplifications on epsilon products
  385. % presently, we limit simplification to the case of TWO epsilons
  386. % for each defined space .
  387. % since more general products are usually not encountered.
  388. if domainp msf then msf
  389. else
  390. begin scalar tens_msf,notens,x,del_prd;
  391. % First see if some simplifications are possible.
  392. tens_msf:=sep_tens_from_other msf;
  393. notens:=cadr tens_msf;
  394. notens:=if notens then notens else !*n2f 1;
  395. tens_msf:=car tens_msf;
  396. if null tens_msf then return msf;
  397. % we have to extract relevant epsilon products from tens_msf
  398. % and construct the DEL-like product
  399. x:=mk_eps_lst tens_msf;
  400. tens_msf:=reverse cadr x;
  401. % function epsi_to_del returns an SF
  402. del_prd:= epsi_to_del car x;
  403. % we do the product of DEL-like tensors and operators.
  404. x:=if del_prd then multf(del_prd,notens)
  405. else notens;
  406. for each j in tens_msf do x:=multf(!*k2f j,x);
  407. % returns tne new SF which is NO LONGER a monomial.
  408. return x
  409. end;
  410. endmodule;
  411. end;