noncom2.red 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. % N O N C O M 2 %
  3. % %
  4. % A Package to redefine %
  5. % noncommutativity in REDUCE %
  6. % %
  7. % Author: Mathias Warns %
  8. % Physics Institute %
  9. % University of Bonn %
  10. % Nussallee 12 %
  11. % D-5300 BONN 1 (F.R.G.) %
  12. % <UNP008@DBNRHRZ1.bitnet> %
  13. % %
  14. % Version: 2.5 06 Jan 92 %
  15. % %
  16. % %
  17. % Designed for: REDUCE version 3.3 / 3.4 %
  18. % Tested on : - IBM 3081/3084/9000-620 VM/CMS MVS/XA %
  19. % SLISP implementation of REDUCE %
  20. % PSL/370 implementation of REDUCE %
  21. % - Intel 386/486 AT compatible %
  22. % PSL implementation of REDUCE %
  23. % %
  24. % Copyright (c) Mathias Warns 1990 - 1992 %
  25. % %
  26. % %
  27. % Permission is granted to any individual or institution to %
  28. % use, copy or re-distribute this software as long as it is %
  29. % not sold for profit, provided that this copyright notice %
  30. % is retained and the file is not altered. %
  31. % %
  32. % **** Summary of changes since version 1.0 **** %
  33. % %
  34. % - Various small bugs have been corrected in the utility %
  35. % functions %
  36. % - The sloppy use of CAR on atoms allowed in SLISP systems has %
  37. % been removed %
  38. % - The pattern matching routine SUBS3TNC has been entirely %
  39. % recoded for greater efficiency and is now used for ALL %
  40. % terms (not only for the noncommuting cases) %
  41. % Procedures SUBLIST, LOCATE!_N and MTCHP1!* added %
  42. % - Enhanced tracing utilities added %
  43. % - NONCOMP has been changed to NONCOMP!* since the former %
  44. % cannot be redefined on some systems %
  45. % 2.0 100691 mw : %
  46. % - deleting functions recoded %
  47. % - append replaced by nconc everywhere %
  48. % - switch MYMATCH added to choose between pattern matchers %
  49. % - procedures NONCOM and NONCOMMUTING modified %
  50. % 2.5 210891 mw %
  51. % - Bug in SUBSTNC corrected and enhanced %
  52. % - procedure ZERLEG added for much faster handling of s. t. %
  53. % - procedure !*SUBS3TNC modfified accordingly %
  54. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  55. %------------------------------------------------------------------
  56. % this package relies on modified standard reduce routines %
  57. % and is therefore version dependent %
  58. %-------------------------------------------------------------------
  59. module noncom2;
  60. fluid '(!*nosq !*mymatch frlis!*); % !*nosq needed for 3.4
  61. !*nosq := t;
  62. switch mymatch;
  63. !*mymatch := t; %this is the default
  64. %------------------------------%
  65. % general utility functions %
  66. %------------------------------%
  67. symbolic procedure trwrite u;
  68. begin scalar x;
  69. if not flagp(car u,'tracing) then return nil;
  70. write "**in procedure: ", car u; terpri();
  71. for each x in cdr u do write x;
  72. terpri();
  73. end;
  74. symbolic procedure funtrace u;
  75. for each x in u do flag(list(x),'tracing);
  76. deflist('((trwrite rlis) (funtrace rlis)),'stat);
  77. symbolic procedure pnth!*(u,n); % slightly modified from pnth
  78. if null u then nil
  79. else if n=1 then u
  80. else pnth!*(cdr u,n-1);
  81. symbolic procedure nth!*(u,n);
  82. if length(u) < n then nil
  83. else car pnth!*(u,n);
  84. symbolic procedure revassoc(u,v); % added 140791 mw
  85. % revesre of assoc
  86. % checks the a-list v for a pair whose CDR is u
  87. begin scalar x;
  88. if not listp v then rederr "invalid argument to revassoc";
  89. a: if null v then return;
  90. x := car v;
  91. v := cdr v;
  92. if (pairp x) and (cdr x = u) then return car x;
  93. go to a;
  94. end;
  95. symbolic procedure kernelp u; %new
  96. % checks if an algebraic expression is a kernel
  97. if null u or domain!*p u then nil
  98. else if idp u then t
  99. else if listp u and idp car u and not (car u memq
  100. '(!*sq set setq plus minus difference times quotient))
  101. then t
  102. else nil;
  103. symbolic procedure spp u; %new
  104. % checks if u is a standard power
  105. pairp u and kernelp car u;
  106. symbolic procedure stp u; %new
  107. % checks if u is a s.t.
  108. pairp u and spp car u;
  109. symbolic procedure sfp2 u; %new
  110. % checks if u if a s.f.
  111. % sfp seems to be ill defined
  112. pairp u and stp car u;
  113. symbolic procedure tstp u; %new
  114. % checks if u is a "true" standard term, i.e. a product term
  115. stp u and (car !*f2a !*t2f u neq 'plus);
  116. symbolic procedure !*!*a2f u; %new
  117. %converts u without call of subs2
  118. begin scalar flg,res;
  119. flg := subfg!*; subfg!* := nil;
  120. res := !*a2f u;
  121. subfg!* := flg;
  122. return res
  123. end;
  124. symbolic procedure !*!*a2q u; %new
  125. %converts an algebraic expression into a s.q. using !*!*a2f
  126. if car u eq 'quotient then !*!*a2f cadr u . !*!*a2f caddr u
  127. else !*f2q !*!*a2f u;
  128. symbolic procedure !*a2q u; %new
  129. %converts an algebraic expression into a s.q. using !*a2f
  130. if (not atom u and car u eq 'quotient) then
  131. !*a2f cadr u . !*a2f caddr u
  132. else !*f2q !*a2f u;
  133. symbolic procedure atsoc2(u,v);
  134. % same as atsoc but looks for the caar part
  135. begin scalar res;
  136. for each x in v do
  137. if (not atom car x and caar x eq u) then res:= x;
  138. return res
  139. end;
  140. symbolic procedure sublist(u,v);
  141. % u and v are lists of sp
  142. % checks if all elements of u are included in v in the right order
  143. % return a sublist of containing the elements of u + the rest of v
  144. begin scalar x,z,y,w,reslist,n,u1;
  145. if not (listp u and listp v) then
  146. rederr " invalid arguments to sublist";
  147. %initialization
  148. if null u or null v or not (V:= member(car u,v)) then return;
  149. a : if null u then return nconc(reslist,append(u1,v));
  150. z:= v;
  151. x := car u;
  152. u := cdr u;
  153. if not (v:= member(x,z)) then return;
  154. v := cdr v;
  155. n:= length(z) - length(v) - 1;
  156. z := for k:= 1 : n collect nth(z,k);
  157. trwrite(sublist,"z= ",z," v= ",v," x= ",x);
  158. a0: if null z then
  159. <<
  160. u1 := nconc(u1,list(x));
  161. go to a;
  162. >>;
  163. w := car z;
  164. z := cdr z;
  165. if noncommuting!_splist(w,u1) then go to a1
  166. else reslist := nconc(reslist,list(w));
  167. go to a0;
  168. a1:
  169. z := reverse (w . z);
  170. if noncommutingsp(car z,x) then return;
  171. v := (car z) . v;
  172. z := reverse cdr z;
  173. go to a0;
  174. end;
  175. symbolic procedure deleteall(x,u); %2.1
  176. % deletes all occurrences of x in u
  177. begin scalar y,res;
  178. a: if null u then return res;
  179. y:= car u;
  180. u := cdr u;
  181. if not (y = x) then res:= nconc(res,list(y));
  182. go to a
  183. end;
  184. symbolic procedure deletemult(x,u); %2.1
  185. % deletes multiples occurences of x in u
  186. % keeping only one left
  187. begin scalar y,n;
  188. if null (y:= cdr member(x,u)) then return u;
  189. n:=length(u)-length(y);
  190. return nconc(for k:=1 :n collect nth(u,k),deleteall(x,y));
  191. end;
  192. symbolic procedure deletemult!* u;
  193. % deletes all multiple occurences of elements in u
  194. begin scalar x;
  195. if null u then return u;
  196. x:=list(car u);
  197. u := cdr u;
  198. for each y in u do
  199. if not member(y,x) then nconc(x,list(y));
  200. return x
  201. end;
  202. symbolic procedure listofvarnames u; %new
  203. % u is a list of s.p.
  204. % returns list of vars in u
  205. % we keep nil as placeholder for numbers in u
  206. if not listp u then rederr "invalid argument to listofvarnames"
  207. else for each x in u collect if domain!*p x then (nil . 'free)
  208. else if atom x then (nil . 'free)
  209. else if idp car x then ((car x) . 'free)
  210. else if idp caar x then ((caar x) . 'free);
  211. symbolic procedure replsublist(u,v,w); %new
  212. % v and w are p-lists
  213. % u is anything
  214. % replaces the sublist v in w by u
  215. begin scalar n,x,res;
  216. if not (x:= sublist(v,w)) then return w;
  217. n:= length(w)-length(x);
  218. % trwrite "n= ",n," x= ",x;
  219. % u := if listp u then u else list(u);
  220. % trwrite "u= ",u,listp u;
  221. res := if zerop n then nil
  222. else for k:= 1 :n collect nth(w,k);
  223. res := if null res then u else nconc(res,u);
  224. % trwrite "res= ",res;
  225. return if (length(v) = length(x)) then res
  226. else nconc(res,pnth(x,length(v)+1))
  227. end;
  228. symbolic procedure locate!_n(x,lst,n);
  229. % returns the position of the n-th occurence of x in lst
  230. % nil if not succesful
  231. begin scalar n2,lst2,ntot;
  232. if null lst then return nil;
  233. lst2 := lst;
  234. ntot:= 0;
  235. a: if n = 0 then return ntot;
  236. n2:= locate_member(x,lst2);
  237. % trwrite "n2=",n2," lst2= ",lst2;
  238. if null n2 then return nil;
  239. lst2 := cdr pnth(lst2,n2);
  240. ntot := ntot+n2;
  241. n:= n-1;
  242. go to a;
  243. end;
  244. symbolic procedure term2listpows u; %new
  245. % u is a s.t. containing only products
  246. % return a list of the s.p. of u
  247. begin
  248. trwrite(term2listpows,"u= ",u);
  249. return
  250. if null u then u
  251. else if atom u then list u
  252. else if domain!*p cdr u then car u . list cdr u
  253. else car u . term2listpows cadr u;
  254. end;
  255. symbolic procedure listprod2term u; %new
  256. % u is a list of product terms (numbers,s.p.,s.t.,s.f.)
  257. % value is the s.q. obtained by multiplying all the terms together
  258. begin scalar x,res;
  259. if not listp u then rederr "invalid argument to listprod2term";
  260. if null u then return u;
  261. res:= car u;
  262. res := if domain!*p res then !*d2q res
  263. else if spp res then !*p2q res else if stp res then !*t2q res
  264. else if sfp2 res then res . 1 else res;
  265. % trwrite "res= ",res;
  266. u :=cdr u;
  267. a: if null u then return res;
  268. x := car u;
  269. x := if domain!*p x then !*d2q x
  270. else if spp x then !*p2q x else if stp x then !*t2q x
  271. else if sfp2 x then x . 1 else x;
  272. u := cdr u;
  273. res := multsq(res,x);
  274. go to a;
  275. end;
  276. % this routine gives the position of an object in a list. the first
  277. % object is numbered 1. returns nil if the object can't be found.
  278. symbolic procedure locate_member(u,v);
  279. if not member(u,v) then nil
  280. else if u=car v then 1
  281. else 1+locate_member(u,cdr v);
  282. global '(domainlist!*);
  283. symbolic procedure domain!*p u;
  284. % this is a much more precise domain checker than domainp
  285. null u or numberp u or (not atom u and memq(car u,domainlist!*));
  286. %------------------------------------------------%
  287. % new defintions of noncom and testing functions %
  288. %------------------------------------------------%
  289. % clear previous definitions of noncom
  290. remflag('(noncom),'flagop);
  291. remprop('noncom,'stat);
  292. symbolic procedure noncomp2 u; % changed
  293. % u is a kernel checks for noncom flag
  294. if atom u then flagp(u,'noncom)
  295. else flagpcar(u,'noncom);
  296. symbolic procedure noncom u; %new
  297. begin scalar y,liste;
  298. if not listp u then rederr(u, "invalid argument to noncom");
  299. for each x in u do <<
  300. if not idp x then rederr(x, "invalid argument to noncom");
  301. flag(list(x),'noncom);
  302. liste:=get(x,'noncommutes);
  303. y := delete(x,u);
  304. put(x,'noncommutes,deletemult!* nconc(liste,y));
  305. % the following is needed for the physop package added 2.1 140891 mw
  306. if (get(x,'rtype) = 'physop) then
  307. <<
  308. flag(list(adjp x),'noncom);
  309. liste:=get(adjp x,'noncommutes);
  310. y := delete(adjp x,for each j in u collect adjp j);
  311. put(adjp x,'noncommutes,deletemult!* nconc(liste,y));
  312. flag(list(invp x),'noncom);
  313. liste:=get(invp x,'noncommutes);
  314. y := delete(invp x,for each j in u collect invp j);
  315. put(invp x,'noncommutes,deletemult!* nconc(liste,y));
  316. >>;
  317. >>;
  318. return nil
  319. end;
  320. deflist('((noncom rlis)),'stat);
  321. symbolic procedure noncommuting(u,v); % modifed 2.1 140891 mw
  322. % u and v are two kernels
  323. % checks for noncommuting
  324. begin scalar list,res;
  325. u := if atom u then u else car u;
  326. v := if atom v then v else car v;
  327. if not (noncomp2 u and noncomp2 v) then nil
  328. else <<
  329. list :=get(u,'noncommutes);
  330. res:=member(v,list);
  331. >>;
  332. return res
  333. end;
  334. symbolic procedure noncommutingterm u; %new
  335. % u is a standard term
  336. % checks if there are some noncommuting products in u
  337. begin scalar x,y;
  338. if null u or domain!*p u or spp u then return nil;
  339. x := tvar u; % <-- term variable
  340. u := cdr u; % <-- tc (s.f.)
  341. a: if null u or domain!*p u then return nil;
  342. y := car u; % <-- lt
  343. if noncommutingf(x,list(y)) or noncommutingterm y then return t;
  344. u := cdr u;
  345. go to a
  346. end;
  347. symbolic procedure noncommutingf(x,u); % new
  348. % x is a kernel, u is a standard form
  349. % checks for noncommuting
  350. if domain!*p u then nil
  351. else noncommuting(x, mvar u) or noncommutingf(x, lc u)
  352. or noncommutingf(x, red u);
  353. symbolic procedure noncommutingsp(u,v);
  354. % u and v are sp or numbers
  355. if null u or null v or numberp u or numberp v then nil
  356. else noncommuting(car u,car v);
  357. symbolic procedure noncommuting!_splist(u,v);
  358. % u is a sp, v is a list of sp
  359. % checks if u commutes with all elements of v
  360. if null v or null u then nil
  361. else noncommutingsp(u,car v) or noncommuting!_splist(u,cdr v);
  362. %----------------------------------%
  363. % modified multiplication routine %
  364. %----------------------------------%
  365. symbolic procedure multf(u,v); % changed
  366. %u and v are standard forms.
  367. %value is standard form for u*v;
  368. begin scalar ncmp,x,y;
  369. a: if null u or null v then return nil
  370. else if u=1 then return v % onep
  371. else if v=1 then return u % onep
  372. else if domainp u then return multd(u,v)
  373. else if domainp v then return multd(v,u)
  374. else if not(!*exp or ncmp!* or wtl!* or x)
  375. then <<u := mkprod u; v := mkprod v; x := t; go to a>>;
  376. x := mvar u;
  377. y := mvar v;
  378. % the following line has been replaced
  379. % if (ncmp:= noncomp2 y) and noncomp2 x then return multfnc(u,v)
  380. if noncommuting(x,y) then return multfnc(u,v)
  381. % we have to put this clause here to prevent evaluation in case
  382. % of equal main vars
  383. else if noncommutingf(y, lc u) or (ordop(x,y) and (x neq y))
  384. then << x := multf(lc u,v);
  385. y := multf(red u,v);
  386. return if null x then y else lpow u .* x .+ y>>
  387. else if x eq y
  388. % two forms have the same mvars
  389. then << x := mkspm(x,ldeg u+ldeg v);
  390. y := addf(multf(red u,v),multf(!*t2f lt u,red v));
  391. return if null x or null(u := multf(lc u,lc v))
  392. then <<!*asymp!* := t; y>>
  393. else if x=1 then addf(u,y)
  394. else if null !*mcd then addf(!*t2f(x .* u),y)
  395. else x .* u .+ y>>;
  396. x := multf(u,lc v);
  397. y := multf(u,red v);
  398. return if null x then y else lpow v .* x .+ y
  399. end;
  400. %--------------------------------------------%
  401. % procedures for ordering of expressions %
  402. %--------------------------------------------%
  403. symbolic procedure ordp(u,v); % modified
  404. %returns true if u ordered ahead or equal to v, nil otherwise.
  405. %an expression with more structure at a given level is ordered
  406. % behind (and not ahead) of one with less;
  407. % ordering of numbers is left as default
  408. if null u then t
  409. else if null v then nil
  410. else if atom u then
  411. if atom v then
  412. if numberp u then
  413. if numberp v then not u < v
  414. else t
  415. else if numberp v then nil
  416. else orderp(u,v)
  417. else t
  418. else if atom v then nil
  419. else if car u=car v then ordp(cdr u,cdr v)
  420. else ordp(car u,car v);
  421. symbolic procedure reordop(u,v); %changed
  422. % modilfied so that every commuting op is ordered ahead
  423. % of every noncommuting op
  424. if noncommuting(u,v) then t
  425. else if noncomp2 u and not noncomp2 v then nil
  426. else if noncomp2 v and not noncomp2 u then t
  427. else ordop(u,v);
  428. %--------------------------------------------------%
  429. % procedures for handling noncommutative %
  430. % terms in pattern matching %
  431. %--------------------------------------------------%
  432. % we have to modify subs3f1 since the handling of noncom mvars
  433. % in subs3t is not correct so we must prevent the system from
  434. % calling this procedure
  435. symbolic procedure subs3f1(u,l,bool); %modified
  436. %u is a standard form.
  437. %l is a list of possible matches.
  438. %bool is a boolean variable which is true if we are at top level.
  439. %value is a standard quotient with all product substitutions made;
  440. begin scalar x,z;
  441. z := nil ./ 1;
  442. a: if null u then return z
  443. else if domainp u then return addsq(z,u ./ 1)
  444. else if bool and domainp lc u then go to c;
  445. % the following line has been changed 2.1
  446. x := if !*mymatch then !*subs3tnc(lt u,l)
  447. else subs3t(lt u,l);
  448. % x := if noncommutingterm lt u then !*subs3tnc(lt u,l)
  449. % else subs3t(lt u,l);
  450. if not bool %not top level;
  451. or not mchfg!* then go to b; %no replacement made;
  452. mchfg!* := nil;
  453. if numr x = u and denr x = 1 then <<x := u ./ 1; go to b>>
  454. % also shows no replacement made (sometimes true with non
  455. % commuting expressions)
  456. else if null !*resubs then go to b
  457. else if !*sub2 or powlis1!* then x := subs2q x;
  458. %make another pass;
  459. x := subs3q x;
  460. b: z := addsq(z,x);
  461. u := cdr u;
  462. go to a;
  463. c: x := list lt u ./ 1;
  464. go to b
  465. end;
  466. symbolic procedure !*subs3tnc(u,v); %new 2.2
  467. % header procedure for subs3tnc
  468. % u is a standard term, v a list of matching templates
  469. % call subs3tnc on every product term of u and return a s.q.
  470. % if u not standard term
  471. begin scalar x,y,res,mchfg;
  472. trwrite('subs3tnc,"before mchfg!*= ",mchfg!*);
  473. if domain!*p u then return !*d2q u;
  474. if kernelp u then return !*k2q u;
  475. if spp u then return !*p2q u;
  476. y := zerleg u; % transform u in a list of true s.t.
  477. trwrite('!*subs3tnc," y= ",y);
  478. res := (nil . 1);
  479. a: if null y then << mchfg!* := mchfg; return res >>;
  480. x := car y;
  481. y := cdr y;
  482. res := addsq(res,subs3tnc(x,v));
  483. if mchfg!* then <<mchfg := mchfg!*; mchfg!* := nil >>;
  484. trwrite('!*subs3tnc,"res= ",res);
  485. go to a
  486. end;
  487. symbolic procedure zerleg u; % new 2.2
  488. % u is a s. t.
  489. % value is a list of termlists
  490. % each termlist contains the s. p. of a true s. t. of u
  491. begin scalar x,res;
  492. if null u then return u;
  493. if domain!*p u then return list u;
  494. x:= car u; % <-- lpow
  495. u := cdr u; % <-- lc
  496. if null u then return list(list(x));
  497. if domain!*p u then return list(list(x,u));
  498. res := zerleg(car u);
  499. res := for each j in res collect (x . j);
  500. if null cdr u then return res
  501. else return append(res,zerleg(x . cdr u));
  502. end;
  503. symbolic procedure subs3tnc(termlist,v); %new
  504. % new version including more general templates
  505. % u is a list of s.p. from a product term in s. t. form (2.2),
  506. % v a list of matching templates.
  507. % value is the s.t. modified by relevant substitutions
  508. % (eg a s.q. in general case)
  509. begin scalar termlist2,templ,temp,tempsp,tempvar,freetemp,rhs,
  510. lhs,bool,boolp,matchinglist,x,y,z,z1,w,w1,termlist3,na,ka,n,k,
  511. prevterml2,nabs; % added 2.2
  512. % return trivial cases removed 2.2
  513. % if domain!*p u then return !*d2q u;
  514. % build a list of s.p. in u
  515. % termlist := term2listpows u; %this line replaced by argument 2.2
  516. % trwrite(subs3tnc, "termlist= ",termlist);
  517. mchfg!* := nil;
  518. % this is the main loop scanning each template
  519. % terminating if no match found
  520. a: if null v then return listprod2term termlist; %changed 2.2
  521. % these are the variable names in termlist moved here 2.2
  522. termlist2:= listofvarnames termlist;
  523. % select a template
  524. templ := car v;
  525. v := cdr v;
  526. % trwrite(subs3tnc," templ= ",templ," v= ",v);
  527. % rhs is an algebraic expression
  528. rhs := nth(templ,3);
  529. % boolean expression to be satisfied by the matching args
  530. bool := cdadr templ;
  531. % flag to indicate if exact power matching required
  532. boolp := caadr templ;
  533. trwrite(subs3tnc, "bool= ",bool," boolp= ",boolp);
  534. % lhs of templ is already a list of s.p.
  535. lhs := car templ;
  536. temp := nil; freetemp := nil; % initialization
  537. % first we separate the lhs in a list of free and of nonfree
  538. % variables
  539. for each x in reverse lhs do
  540. if memq(car x,frlis!*) then freetemp := x . freetemp
  541. else temp := x . temp;
  542. lhs := nil; % will be rebuilt later on
  543. trwrite(subs3tnc, "temp= ",temp,"freetemp= ",freetemp);
  544. if null temp then go to b;
  545. % we allow nonexact power matching only in the case of 2 sp in lhs
  546. boolp := if length(temp) = 2 then boolp
  547. else t;
  548. k := 1; % counter for number of terms in lhs
  549. na:= 1;
  550. nabs := 0; % added 2.2
  551. z1 := nil;
  552. matchinglist := nil;
  553. a1: if (k > length(temp)) then go to b;
  554. aa: if (k < na) then go to a;
  555. tempsp := nth(temp,k);
  556. tempvar := if idp car tempsp then car tempsp
  557. else caar tempsp;
  558. a2: n:= locate_member((tempvar . 'free),termlist2);
  559. if numberp n then go to ab;
  560. k := k-1;
  561. z1 := nil;
  562. lhs := if null lhs then lhs
  563. else cdr lhs;
  564. % 2.2 two lines added 210891 mw
  565. termlist2 := prevterml2;
  566. nabs := length(termlist) - length(termlist2); % update nabs
  567. go to aa;
  568. ab: % mark tempvar as being used in the pattern matching process
  569. termlist2 :=nconc(for k:=1 :(n-1) collect nth(termlist2,k),
  570. ((tempvar . 'used) . pnth(termlist2,n+1)));
  571. % trwrite(subs3tnc, "termlist2= ",termlist2);
  572. x:= nth(termlist,n+nabs); %2.2 modified to get the absolute position
  573. z:= mtchp1!*(x,tempsp,boolp,bool,z1);
  574. if null cdr z then go to a2;
  575. if car z then
  576. <<
  577. if not sublist(car z ,matchinglist) then
  578. matchinglist:= nconc(matchinglist,car z);
  579. trwrite(subs3tnc, "matchinglist= ",matchinglist);
  580. % do the substitutions of car z in temp and bool
  581. for each y in car z do
  582. <<
  583. bool := subst(cdr y,car y,bool);
  584. temp := subst(cdr y,car y,temp)
  585. >>;
  586. >>;
  587. lhs := x . lhs;
  588. trwrite(subs3tnc, "lhs= ",lhs);
  589. z1:= cdr z;
  590. na:= k;
  591. k:= k + 1;
  592. % 2.2: 3 lines added 210891 mw
  593. prevterml2 := termlist2;
  594. termlist2 := pnth!*(termlist2,n+1);
  595. nabs := nabs + n; %update the absolute position counter
  596. go to a1;
  597. b: if not sublist(car z1,matchinglist) then
  598. matchinglist:= nconc(matchinglist,car z1);
  599. % special hack for nonexact power matching
  600. if (length(lhs) = 2) then
  601. <<
  602. x := cadr lhs; % this is the first term !
  603. y := nth(temp,1);
  604. if ((na:= cdr y) neq (ka := cdr x)) then
  605. <<
  606. termlist := replsublist(list(car x .** (ka - na),
  607. car x .** na),
  608. list(car x .** ka),termlist);
  609. w := list(car x . na);
  610. >>
  611. else w:= list(x);
  612. x:= car lhs; % this is the second term
  613. y := nth(temp,2);
  614. if (na:= cdr y) neq (ka := cdr x) then
  615. <<
  616. termlist := replsublist(list(car x .** na,
  617. car x .** (ka - na)),
  618. list(car x .** ka),termlist);
  619. lhs := (car x . na) . w;
  620. >>
  621. else lhs := x . w;
  622. >>;
  623. % from here on in principle all the terms in lhs are matched
  624. lhs := reverse lhs;
  625. % cross check
  626. if null (termlist3 := sublist(lhs,termlist)) then go to a;
  627. n := length(termlist)-length(termlist3);
  628. % trwrite(subs3tnc, "n= ",n);
  629. % rebuild the termlist after rearrangement
  630. termlist := nconc(for k := 1 : n collect nth(termlist,k),
  631. termlist3);
  632. na := length(freetemp);
  633. if (na = 0) then go to d;
  634. freetemp := reverse freetemp;
  635. % recalculation of n is necessary because lhs do not sit
  636. % in front of termlist3
  637. n:= length(termlist) - length(member(car lhs,termlist));
  638. % match the free variable(s) to be placed in front
  639. if (n < na) then go to a;
  640. % take all the terms in front in this case
  641. if (na = 1) and (cdar freetemp = 1) then
  642. <<
  643. lhs := termlist;
  644. matchinglist:= nconc(matchinglist,list(caar freetemp .
  645. !*q2a listprod2term nconc(
  646. for k:=1 :n collect nth(termlist,k),
  647. for k:= (length(lhs)+1) : length(termlist3)
  648. collect nth(termlist3,k))));
  649. >>
  650. else for k:=1 :na do
  651. <<
  652. x := nth(termlist,n-k+1);
  653. y := nth(freetemp,k);
  654. z:= mtchp1(x,y,boolp,bool);
  655. if not sublist(car z ,matchinglist) then
  656. matchinglist:= nconc(matchinglist,car z);
  657. for each w in car z do
  658. y:= subst(cdr w,car w,y);
  659. lhs := y . lhs;
  660. if (na:= cdr y) neq (ka := cdr x) then
  661. <<
  662. termlist := replsublist(list(car x .** (ka - na),
  663. car x .** na),list(car x .** ka),termlist);
  664. n:= n+1;
  665. >>
  666. >>;
  667. d:
  668. trwrite(subs3tnc,"lhs= ",lhs);
  669. trwrite(susb3tnc," termlist= ",termlist);
  670. % trwrite(subs3tnc,"matchinglist= ",matchinglist);
  671. % replace the free variables in the rhs
  672. for each x in matchinglist do
  673. rhs:= subst(cdr x, car x,rhs);
  674. % trwrite(subs3tnc," rhs= ",rhs);
  675. % and finally we replace the lhs in u by the rhs
  676. % for this we have to replace in the termlist the s.p. of lhs by
  677. % the rhs converted to a standard quotient
  678. rhs := list(simp rhs);
  679. trwrite(subs3tnc," rhs= ",rhs);
  680. termlist:= replsublist(rhs,lhs,termlist);
  681. trwrite(subs3tnc, "resulting termlist = ",termlist);
  682. mchfg!* := t;
  683. return listprod2term termlist
  684. end;
  685. symbolic procedure mtchp1!*(u,v,boolp,bool,z);
  686. % u is a sp, v is a sp to be matched against x
  687. % boolp is a flg (t if exact power matching required)
  688. % bool is a boolean expr to be satisfied during matching
  689. % z is a list of possible matchings for the free variables in y
  690. % returns a list of matching pair lists first is that element of z
  691. % which leads to a succesful matching or nil
  692. begin scalar temp1,bool1,x,z1;
  693. if null z then return nconc(list(nil),mtchp2(u,v,boolp,bool));
  694. a: if null z then return list(nil);
  695. x:= car z;
  696. z:= cdr z;
  697. % trwrite "x= ",x," z= ",z;
  698. temp1:= v;
  699. bool1 := bool;
  700. for each w in x do
  701. <<
  702. temp1:= subst(cdr w,car w, temp1);
  703. bool1 := subst(cdr w,car w,bool1);
  704. >>;
  705. if (z1:=mtchp2(u,temp1,boolp,bool1)) then return x . z1;
  706. go to a;
  707. end;
  708. symbolic procedure mtchp2(u,v,boolp,bool);
  709. % does the same job as mtchp1 but more accurately
  710. % since mtchp1 does not check bool at all
  711. begin scalar z,x,reslist,bool1,bool2;
  712. z := reverse mtchp1(u,v,boolp,bool);
  713. if (bool = t) then return z;
  714. a: if null z then return reslist;
  715. x := car z;
  716. z := cdr z;
  717. bool1 := bool;
  718. for each w in x do bool1 := subst(cdr w,car w,bool1);
  719. bool2:= bool1;
  720. % trick used here to check for remaining free variables in bool
  721. for each w in frlis!* do bool2:=subst(nil,w, bool2);
  722. trwrite(mtchp2, "bool1= ",bool1," bool2= ",bool2);
  723. if ((bool2 = bool1) and null eval bool1) then return nil
  724. else reslist := x . reslist;
  725. go to a
  726. end;
  727. endmodule;
  728. end;