compact.red 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. module compact; % Header module for compact code.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1989 The RAND Corporation. All Rights Reserved.
  4. create!-package('(compact mv mvmatch reddom compactf comfac),
  5. '(contrib compact));
  6. endmodule;
  7. module mv; % Operations on multivariate forms.
  8. % Author: Anthony C. Hearn.
  9. % Copyright (c) 1989 The RAND Corporation. All Rights Reserved.
  10. symbolic smacro procedure mv!-!.!+(u,v); u . v;
  11. symbolic smacro procedure mv!-!.!*(u,v); u . v;
  12. symbolic smacro procedure mv!-lc u; cdar u;
  13. symbolic smacro procedure mv!-lpow u; caar u;
  14. symbolic smacro procedure mv!-lt u; car u;
  15. symbolic smacro procedure mv!-red u; cdr u;
  16. symbolic smacro procedure mv!-term!-coeff u; cdr u;
  17. symbolic smacro procedure mv!-term!-pow u; car u;
  18. symbolic smacro procedure mv!-tpow u; car u;
  19. symbolic smacro procedure mv!-tc u; cdr u;
  20. symbolic procedure mv!-!+(u,v);
  21. if null u then v
  22. else if null v then u
  23. else if mv!-lpow u= mv!-lpow v
  24. then (lambda x;
  25. if x=0 then mv!-!+(mv!-red u,mv!-red v)
  26. else mv!-!.!+(mv!-!.!*(mv!-lpow u,x),
  27. mv!-!+(mv!-red u,mv!-red v)))
  28. (mv!-lc u + mv!-lc v)
  29. else if mv!-pow!-!>(mv!-lpow u,mv!-lpow v)
  30. then mv!-!.!+(mv!-lt u,mv!-!+(mv!-red u,v))
  31. else mv!-!.!+(mv!-lt v,mv!-!+(u,mv!-red v));
  32. symbolic smacro procedure domain!-!*(u,v); u*v;
  33. symbolic smacro procedure domain!-!/(u,v); u/v;
  34. symbolic procedure mv!-term!-!*(u,v);
  35. % U is a (non-zero) term and v a multivariate form. Result is
  36. % product of u and v.
  37. if null v then nil
  38. else mv!-!.!+(mv!-!.!*(mv!-pow!-!+(mv!-tpow u,mv!-lpow v),
  39. domain!-!*(mv!-tc u,mv!-lc v)),
  40. mv!-term!-!*(u,mv!-red v));
  41. symbolic procedure mv!-term!-!/(u,v);
  42. % Returns the result of the (exact) division of u by term v.
  43. if null u then nil
  44. else mv!-!.!+(mv!-!.!*(mv!-pow!-!-(mv!-lpow u,mv!-tpow v),
  45. domain!-!/(mv!-lc u,mv!-tc v)),
  46. mv!-term!-!/(mv!-red u,v));
  47. symbolic procedure mv!-domainlist u;
  48. if null u then nil
  49. else mv!-lc u . mv!-domainlist mv!-red u;
  50. symbolic procedure mv!-pow!-mv!-!+(u,v);
  51. if null v then nil
  52. else mv!-!.!+(mv!-pow!-mv!-term!-!+(u,mv!-lt v),
  53. mv!-pow!-mv!-!+(u,mv!-red v));
  54. symbolic procedure mv!-pow!-mv!-term!-!+(u,v);
  55. mv!-!.!*(mv!-pow!-!+(u,mv!-term!-pow v), mv!-term!-coeff v);
  56. symbolic procedure mv!-pow!-!+(u,v);
  57. if null u then nil
  58. else (car u+car v) . mv!-pow!-!+(cdr u,cdr v);
  59. symbolic procedure mv!-pow!-!-(u,v);
  60. if null u then nil
  61. else (car u-car v) . mv!-pow!-!-(cdr u,cdr v);
  62. symbolic procedure mv!-pow!-!*(u,v);
  63. if null v then nil
  64. else (u*car v) . mv!-pow!-!*(u,cdr v);
  65. symbolic procedure mv!-pow!-minusp u;
  66. if null u then nil
  67. else car u<0 or mv!-pow!-minusp cdr u;
  68. symbolic procedure mv!-pow!-!>(u,v);
  69. if null u then nil
  70. else if car u=car v then mv!-pow!-!>(cdr u,cdr v)
  71. else car u>car v;
  72. symbolic procedure mv!-reduced!-coeffs u;
  73. % reduce coefficients of u to lowest terms.
  74. begin scalar x,y;
  75. x := mv!-lc u;
  76. y := mv!-red u;
  77. while y and x neq 1 do <<x := gcdn(x,mv!-lc y); y := mv!-red y>>;
  78. return if x=1 then u else mv!-!/(u,x)
  79. end;
  80. symbolic procedure mv!-!/(u,v);
  81. if null u then nil
  82. else mv!-!.!+(mv!-!.!*(mv!-lpow u,mv!-lc u/v),mv!-!/(mv!-red u,v));
  83. % Functions that convert between standard forms and multivariate forms.
  84. symbolic procedure sf2mv(u,varlist);
  85. % Converts the standard form u to a multivariate form wrt varlist.
  86. sf2mv1(u,nil,varlist);
  87. symbolic procedure sf2mv1(u,powers,varlist);
  88. if null u then nil
  89. else if domainp u
  90. then list(append(powers,nzeros length varlist) . u)
  91. else if mvar u = car varlist % This should be eq, but seems to
  92. % need equal.
  93. then append(sf2mv1(lc u,append(powers,list ldeg u),cdr varlist),
  94. sf2mv1(red u,powers,varlist))
  95. else sf2mv1(u,append(powers,list 0),cdr varlist);
  96. symbolic procedure nzeros n; if n=0 then nil else 0 . nzeros(n-1);
  97. symbolic procedure mv2sf(u,varlist);
  98. % converts the multivariate form u to a standard form wrt varlist.
  99. % This version uses addf to fold terms - there is probably a more
  100. % direct method.
  101. if null u then nil
  102. else addf(mv2sf1(mv!-lpow u,cdar u,varlist),mv2sf(cdr u,varlist));
  103. symbolic procedure mv2sf1(powers,cf,varlist);
  104. if null powers then cf
  105. else if car powers=0 then mv2sf1(cdr powers,cf,cdr varlist)
  106. else !*t2f((car varlist .** car powers)
  107. .* mv2sf1(cdr powers,cf,cdr varlist));
  108. endmodule;
  109. module mvmatch; % Side relation matching against expressions.
  110. % Author: Anthony C. Hearn.
  111. % Copyright (c) 1991 The RAND Corporation. All Rights Reserved.
  112. symbolic procedure mv!-compact(u,v,w);
  113. % Compares a multivariate form u with a multivariate form template v
  114. % and reduces u appropriately.
  115. % Previously, the content was removed from u. However, this does
  116. % not work well if the same content is in v.
  117. begin scalar x,y; % z;
  118. if null u then return mv!-reverse w;
  119. % if null w then <<z := mv!-content u; u := mv!-term!-!/(u,z)>>
  120. % else z := nzeros length mv!-lpow u . 1;
  121. % check first terms.
  122. if (x := mv!-pow!-chk(u,v))
  123. and (y := mv!-compact2(u,mv!-pow!-mv!-!+(x,v)))
  124. % then return mv!-term!-!*(z,mv!-compact(y,v,w))
  125. then return mv!-compact(y,v,w)
  126. % check second terms.
  127. else if (x := mv!-pow!-chk(u,mv!-red v))
  128. and not mv!-pow!-assoc(y := mv!-pow!-!+(x,mv!-lpow v),w)
  129. and (y := mv!-compact2(mv!-!.!+(mv!-!.!*(y,0),u),
  130. mv!-pow!-mv!-!+(x,v)))
  131. % then return mv!-term!-!*(z,mv!-compact(y,v,w))
  132. % else return mv!-term!-!*(z,mv!-compact(mv!-red u,v,mv!-lt u . w))
  133. then return mv!-compact(y,v,w)
  134. else return mv!-compact(mv!-red u,v,mv!-lt u . w)
  135. end;
  136. symbolic procedure mv!-pow!-assoc(u,v); assoc(u,v);
  137. symbolic procedure mv!-reverse u; reversip u;
  138. symbolic procedure mv!-pow!-chk(u,v);
  139. % (u := mv!-pow!-!-(caar u,caar v)) and not mv!-pow!-minusp u and u;
  140. if v and (u := mv!-pow!-!-(caar u,caar v)) and not mv!-pow!-minusp u
  141. then u
  142. else nil;
  143. symbolic procedure mv!-compact2(u,v);
  144. % U and v are multivariate forms whose first powlists are equal.
  145. % Value is a suitable multiplier of v which when subtracted from u
  146. % results in a more compact expression.
  147. begin scalar x,y,z;
  148. x := equiv!-coeffs(u,v);
  149. z := mv!-domainlist v;
  150. y := reduce(x,z);
  151. return if y=x then nil
  152. else mv!-!+(mv!-coeff!-replace(v,mv!-domainlist!-!-(y,x)),u)
  153. end;
  154. symbolic procedure mv!-coeff!-replace(u,v);
  155. % Replaces coefficients of multivariate form u by those in domain
  156. % list v.
  157. if null u then nil
  158. else if car v=0 then mv!-coeff!-replace(mv!-red u,cdr v)
  159. else mv!-!.!+(mv!-!.!*(mv!-lpow u,car v),
  160. mv!-coeff!-replace(mv!-red u,cdr v));
  161. symbolic procedure equiv!-coeffs(u,v);
  162. if null u then nzeros length v
  163. else if null v then nil
  164. else if mv!-lpow u = mv!-lpow v
  165. then cdar u . equiv!-coeffs(cdr u,cdr v)
  166. else if mv!-pow!-!>(mv!-lpow u,mv!-lpow v)
  167. then equiv!-coeffs(cdr u,v)
  168. else 0 . equiv!-coeffs(u,cdr v);
  169. endmodule;
  170. module reddom; % Reduction of domain elements.
  171. % Author: Anthony C. Hearn.
  172. % Copyright (c) 1989 The RAND Corporation. All Rights Reserved.
  173. fluid '(mv!-vars!*);
  174. global '(!*xxx !*yyy);
  175. switch xxx,yyy;
  176. !*xxx := !*yyy := t;
  177. % Operations on domain elements.
  178. symbolic smacro procedure domain!-!+(u,v); u+v;
  179. symbolic smacro procedure domain!-!-(u,v); u-v;
  180. symbolic smacro procedure domain!-!*(u,v); u*v;
  181. symbolic smacro procedure domain!-divide(u,v); divide(u,v);
  182. % Operations on domain element lists.
  183. symbolic procedure mv!-domainlist!-!+(u,v);
  184. if null u then nil
  185. else domain!-!+(car u,car v) . mv!-domainlist!-!+(cdr u,cdr v);
  186. symbolic procedure mv!-domainlist!-!-(u,v);
  187. if null u then nil
  188. else domain!-!-(car u,car v) . mv!-domainlist!-!-(cdr u,cdr v);
  189. symbolic procedure mv!-domainlist!-!*(u,v);
  190. if null v then nil
  191. else domain!-!*(u,car v) . mv!-domainlist!-!*(u,cdr v);
  192. % Procedures for actually reducing domain elements.
  193. symbolic procedure reduce(u,v);
  194. % Reduce domain element list u with respect to an equal length domain
  195. % element list v. We assume that v has been reduced to lowest terms.
  196. begin scalar weightlist,x;
  197. % Look for equal ratios of elements.
  198. x := u;
  199. if !*yyy then
  200. x := reduce!-ratios(x,v);
  201. % Define weighting list.
  202. weightlist := set!-weights v;
  203. % Choose column elimination with lowest weight.
  204. if !*xxx then
  205. x := reduce!-columns(x,v,weightlist);
  206. % Look for a reduction in weight of the expression.
  207. if !*xxx then
  208. x := reduce!-weights(x,v,weightlist);
  209. return x
  210. end;
  211. symbolic procedure set!-weights v;
  212. % Define weights to be associated with the reduction test.
  213. % The current definition is pretty naive.
  214. begin integer n;
  215. % return reversip for each j in v collect (n := n+1)
  216. return reversip (0 . for each j in cdr v collect 1)
  217. end;
  218. symbolic procedure reduce!-ratios(u,v);
  219. begin scalar x;
  220. if null(x := red!-ratios1(u,v)) then return u;
  221. x := mv!-domainlist!-!-(mv!-domainlist!-!*(car x,u),
  222. mv!-domainlist!-!*(cdr x,v));
  223. return if zeros u >= zeros x then u
  224. else reduce!-ratios(x,v)
  225. end;
  226. symbolic procedure zeros u;
  227. if null u then 0
  228. else if car u = 0 then 1+zeros cdr u
  229. else zeros cdr u;
  230. symbolic procedure red!-ratios1(u,v);
  231. u and (red!-ratios2(cdr u,cdr v,car u,car v)
  232. or red!-ratios1(cdr u,cdr v));
  233. symbolic procedure red!-ratios2(u,v,u1,v1);
  234. begin integer n;
  235. return if null u then nil
  236. else if (n := u1*car v) = v1*car u and n neq 0
  237. then red!-lowest!-terms(v1,u1)
  238. else red!-ratios2(cdr u,cdr v,u1,v1)
  239. end;
  240. symbolic procedure red!-lowest!-terms(u,v);
  241. begin scalar x;
  242. if u<0 then <<u := -u; v := -v>>;
  243. x := gcdn(u,v);
  244. % We must have x = u otherwise the reduction has the
  245. % wrong factor.
  246. if x neq u then errach list("red-lowest-terms",u,v);
  247. return 1 . (v/x)
  248. end;
  249. symbolic procedure reduce!-columns(u,v,weightlist);
  250. begin scalar w,x,y,z,z1;
  251. x := u;
  252. y := v;
  253. w := (u . red!-weight(u,weightlist));
  254. a: if null x then return car w
  255. else if car x=0 or car y=0 then nil
  256. else if cdr(z := domain!-divide(car x,car y))=0
  257. then <<z := mv!-domainlist!-!-(u,mv!-domainlist!-!*(car z,v));
  258. z1 := red!-weight(z,weightlist);
  259. if red!-weight!-less!-p(z1,cdr w)
  260. and not more!-apartp(z . z1,w)
  261. then w := (z . z1)>>;
  262. x := cdr x;
  263. y := cdr y;
  264. go to a
  265. end;
  266. symbolic procedure more!-apartp(u,v);
  267. cadr u=2 and cadr u=cadr v and cadar u=0 and cadar v neq 0;
  268. symbolic procedure reduce!-weights(u,v,weightlist);
  269. begin scalar success,x,y,z;
  270. x := red!-weight(u,weightlist);
  271. a: y := mv!-domainlist!-!+(u,v);
  272. z := red!-weight(y,weightlist);
  273. if red!-weight!-less!-p(z,x)
  274. then <<success := t; u := y; x := z; go to a>>;
  275. if success then return u;
  276. b: y := mv!-domainlist!-!-(u,v);
  277. z := red!-weight(y,weightlist);
  278. if red!-weight!-less!-p(z,x) then <<u := y; x := z; go to b>>;
  279. return u
  280. end;
  281. symbolic procedure red!-weight(u,weightlist);
  282. nonzero!-length u . red!-weight1(u,weightlist);
  283. symbolic procedure red!-weight1(u,weightlist);
  284. if null u then 0
  285. else abs car u*car weightlist
  286. + red!-weight1(cdr u,cdr weightlist);
  287. symbolic procedure nonzero!-length u;
  288. if null u then 0
  289. else if car u=0 then nonzero!-length cdr u
  290. else add1 nonzero!-length cdr u;
  291. symbolic procedure red!-weight!-less!-p(u,v);
  292. if car u=car v then cdr u<cdr v else car u<car v;
  293. endmodule;
  294. module compactf; % Algorithms for compacting algebraic expressions.
  295. % Author: Anthony C. Hearn.
  296. % Copyright (c) 1991 The RAND Corporation. All Rights Reserved.
  297. fluid '(mv!-vars!*);
  298. global '(!*trcompact);
  299. switch trcompact;
  300. % Interface to REDUCE simplifier.
  301. put('compact,'simpfn,'simpcompact);
  302. symbolic procedure simpcompact u;
  303. begin scalar bool;
  304. if null u or null cdr u
  305. then rerror(compact,1,
  306. list("Wrong number of arguments to compact"));
  307. if null !*exp then <<rmsubs(); bool := !*exp := t>>;
  308. u := errorset!*(list('simpcompact1,mkquote u),nil);
  309. if bool then !*exp := nil;
  310. if errorp u then rerror(compact,2,"Compact error");
  311. return car u
  312. end;
  313. symbolic procedure simpcompact1 u;
  314. begin scalar v,x;
  315. v := simp!* car u;
  316. u := cadr u;
  317. if idp u
  318. then if eqcar(x := get(u,'avalue),'list)
  319. then u := cadr x
  320. else typerr(u,"list")
  321. else if getrtype u eq 'list then u := cdr u
  322. else typerr(u,"list");
  323. u := for each j in u collect if not eqcar(j,'equal) then j
  324. else !*eqn2a j;
  325. for each j in u do v := compactsq(v,simp!* j);
  326. return v
  327. end;
  328. % True beginning of compacting routines.
  329. symbolic procedure compactsq(u,v);
  330. % U is a standard quotient, v a standard quotient for equation v=0.
  331. % Result is a standard quotient for u reduced wrt v=0.
  332. begin
  333. if denr v neq 1
  334. then msgpri("Relation denominator",prepf denr v,"discarded",
  335. nil,nil);
  336. v := numr v;
  337. return multsq(compactf(numr u,v) ./ 1,
  338. 1 ./ compactf(denr u,v))
  339. end;
  340. symbolic procedure compactf(u,v);
  341. % U is a standard form, v a standard form for an equation v=0.
  342. % Result is a standard form for u reduced wrt v=0.
  343. begin scalar x; integer n;
  344. if !*trcompact
  345. then <<prin2t "*** Arguments on entering compactf:";
  346. mathprint mk!*sq !*f2q u;
  347. mathprint mk!*sq !*f2q v>>;
  348. while x neq u do <<x := u; u := compactf1(u,v); n := n+1>>;
  349. if !*trcompact and n>2
  350. then <<prin2 " *** Compactf looped ";prin2 n; prin2t " times">>;
  351. return u
  352. end;
  353. symbolic procedure compactf1(u,v);
  354. begin scalar x,y,z;
  355. x := kernels u;
  356. y := kernels v;
  357. z := intersection(x,y); % find common vars.
  358. if null z then return u;
  359. % Unfortunately, it's too expensive in space to generate all perms.
  360. % as in this example:
  361. % l:={-c31*c21+c32*c22+c33*c23+c34*c24=t1};
  362. % x:= -c31*c21+c32*c22+c33*c23+c34*c24;
  363. % compact(x,l); % out of heap space
  364. % for each j in permutations z do u := compactf11(u,v,x,y,j);
  365. return compactf11(u,v,x,y,z)
  366. % return u
  367. end;
  368. symbolic procedure compactf11(u,v,x,y,z);
  369. begin scalar w;
  370. if domainp u then return u;
  371. y := append(z,setdiff(y,z)); % vars in eqn.
  372. x := append(setdiff(x,z),y); % all vars.
  373. x := setkorder x;
  374. u := reorder u; % reorder expressions.
  375. v := reorder v;
  376. z := comfac!-to!-poly comfac u;
  377. u := quotf(u,z);
  378. u := remchkf(u,v,y);
  379. w := compactf2(u,mv!-reduced!-coeffs sf2mv(v,y),y);
  380. if termsf w < termsf u then u := w;
  381. % Should we also reduce z at this point?
  382. u := multf(z,u);
  383. % It is possible that if z is not a kernel product, that including
  384. % z in the reduction can lead to a more compact form, but we
  385. % exclude that case for the time being.
  386. setkorder x;
  387. u := reorder u;
  388. if !*trcompact
  389. then <<prin2t "*** Value on leaving compactf11:";
  390. mathprint mk!*sq !*f2q u>>;
  391. return u
  392. end;
  393. symbolic procedure remchkf(u,v,vars);
  394. % This procedure returns u after checking if a smaller remainder
  395. % results after division by v. It is potentially inefficient, since
  396. % we check all the way down the list, term by term. However, the
  397. % process terminates when we no longer have any relevant kernels.
  398. (if domainp x or null intersection(kernels u,vars) then x
  399. else lt x .+ remchkf(red x,v,vars))
  400. where x=remchkf1(u,v);
  401. symbolic procedure remchkf1(u,v);
  402. begin integer n;
  403. n := termsf u;
  404. v := xremf(u,v,n);
  405. if null v or termsf(v := car v)>=n then return u
  406. else if !*trcompact then prin2t "*** Remainder smaller";
  407. return v
  408. end;
  409. symbolic procedure xremf(u,v,m);
  410. % Returns the quotient and remainder of U divided by V, or NIL if
  411. % the number of terms in the remainder exceeds M.
  412. % The goal is to keep terms u+terms z<=m.
  413. % There is some slop in the count, so one must check sizes on
  414. % leaving.
  415. begin integer m1,m2,n; scalar x,y,z;
  416. if domainp v then return list cdr qremd(u,v);
  417. m2 := termsf u;
  418. a: if m<= 0 then return nil
  419. else if domainp u then return list addf(z,u)
  420. else if mvar u eq mvar v
  421. then if (n := ldeg u-ldeg v)<0 then return list addf(z,u)
  422. else <<x := qremf(lc u,lc v);
  423. y := multpf(lpow u,cdr x);
  424. m := m+m1;
  425. z := addf(z,y);
  426. m1 := termsf z;
  427. m := m-m1+m2;
  428. u := if null car x then red u
  429. else addf(addf(u,multf(if n=0 then v
  430. else multpf(mvar u .** n,v),
  431. negf car x)), negf y);
  432. m2 := termsf u;
  433. m := m-m2;
  434. go to a>>
  435. else if not ordop(mvar u,mvar v) then return list addf(z,u);
  436. m := m+m1;
  437. x := xremf(lc u,v,m);
  438. if null x then return nil;
  439. z := addf(z,multpf(lpow u,car x));
  440. m1 := termsf z;
  441. m := m-m1;
  442. u := red u;
  443. go to a
  444. end;
  445. symbolic procedure compactf2(u,v,vars);
  446. % U is standard form for expression, v for equation. W is ordered
  447. % list of variables in v. Result is a compacted form for u.
  448. if domainp u then u
  449. else if mvar u memq vars then compactf3(u,v,vars)
  450. else lpow u .* compactf2(lc u,v,vars) .+ compactf2(red u,v,vars);
  451. symbolic procedure compactf3(u,v,vars);
  452. begin scalar mv!-vars!*;
  453. mv!-vars!* := vars;
  454. return mv2sf(mv!-compact(sf2mv(u,vars),v,nil),vars)
  455. end;
  456. endmodule;
  457. module comfac; % Multivariate common factor/content routines.
  458. % Author: Anthony C. Hearn.
  459. % Copyright (c) 1989 The RAND Corporation. All Rights Reserved.
  460. symbolic smacro procedure domain!-gcd(u,v); gcdn(u,v);
  461. symbolic smacro procedure domain!-onep u; onep u;
  462. symbolic procedure mv!-pow!-zerop u;
  463. null u or zerop car u and mv!-pow!-zerop cdr u;
  464. symbolic procedure mv!-pow!-gcd(u,v);
  465. if null u then nil
  466. else min(car u,car v) . mv!-pow!-gcd(cdr u,cdr v);
  467. symbolic procedure mv!-content u;
  468. % Finds the term that is the content of u.
  469. if null u then nil
  470. else begin scalar x,y;
  471. x := mv!-lc u;
  472. y := mv!-lpow u;
  473. a: u := mv!-red u;
  474. if null u or domain!-onep x and mv!-pow!-zerop y
  475. then return mv!-!.!*(y,x);
  476. x := domain!-gcd(x,mv!-lc u);
  477. y := mv!-pow!-gcd(y,mv!-lpow u);
  478. go to a
  479. end;
  480. endmodule;
  481. end;