noncom2.red 25 KB

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