polrep.red 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. module polrep; % Arithmetic operations on standard forms and quotients.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 RAND. All rights reserved.
  4. fluid '(!*asymp!* !*exp !*factor !*gcd !*lcm !*mcd !*rationalize frlis!*
  5. !*roundall !*rounded !*sqfree !*sub2 asymplis!* dmode!* subfg!*
  6. ncmp!* powlis!* wtl!* !*!*processed !*ncmp);
  7. global '(!*group rd!-tolerance!* cr!-tolerance!*);
  8. put('roundall,'simpfg,'((t (rmsubs))));
  9. switch roundall;
  10. !*roundall := t; % Default is on.
  11. symbolic smacro procedure subtrsq(u,v); addsq(u,negsq v);
  12. symbolic procedure addsq(u,v);
  13. % U and V are standard quotients.
  14. % Value is canonical sum of U and V.
  15. if null numr u then v
  16. else if null numr v then u
  17. else if denr u=1 and denr v=1 then addf(numr u,numr v) ./ 1
  18. else begin scalar x,y,z;
  19. if null !*exp then <<u := numr u ./ mkprod denr u;
  20. v := numr v ./ mkprod denr v>>;
  21. if !*lcm then x := gcdf!*(denr u,denr v)
  22. else x := gcdf(denr u,denr v);
  23. z := canonsq(quotf(denr u,x) ./ quotf(denr v,x));
  24. y := addf(multf(denr z,numr u),multf(numr z,numr v));
  25. if null y then return nil ./ 1;
  26. z := multf(denr u,denr z);
  27. return if x=1 or (x := gcdf(y,x))=1 then y ./ z
  28. else canonsq(quotf(y,x) ./ quotf(z,x))
  29. end;
  30. symbolic procedure multsq(u,v);
  31. % U and V are standard quotients.
  32. % Value is canonical product of U and V.
  33. if null numr u or null numr v then nil ./ 1
  34. else if denr u=1 and denr v=1 then multf(numr u,numr v) ./ 1
  35. else begin scalar x,y,z;
  36. x := gcdf(numr u,denr v);
  37. y := gcdf(numr v,denr u);
  38. z := multf(quotf(numr u,x),quotf(numr v,y));
  39. x := multf(quotf(denr u,y),quotf(denr v,x));
  40. return canonsq(z ./ x)
  41. end;
  42. symbolic procedure negsq u; negf numr u ./ denr u;
  43. smacro procedure multpq(u,v);
  44. multsq(!*p2q u,v);
  45. symbolic procedure cancel u;
  46. %returns canonical form of non-canonical standard form U;
  47. if !*mcd or denr u=1 then multsq(numr u ./ 1,1 ./ denr u)
  48. else multsq(numr u ./ 1,simpexpt list(mk!*sq(denr u ./ 1),-1));
  49. % ***** FUNCTIONS FOR ADDING AND MULTIPLYING STANDARD FORMS *****
  50. symbolic smacro procedure peq(u,v);
  51. %tests for equality of powers U and V;
  52. u = v;
  53. symbolic procedure addf(u,v);
  54. % U and V are standard forms. Value is standard form for U+V.
  55. if null u then v
  56. else if null v then u
  57. else if domainp u then addd(u,v)
  58. else if domainp v then addd(v,u)
  59. else if peq(lpow u,lpow v)
  60. then (if null x then y else lpow u .* x .+ y)
  61. where x=addf(lc u,lc v),y=addf(red u,red v)
  62. else if ordpp(lpow u,lpow v) then lt u .+ addf(red u,v)
  63. else lt v .+ addf(u,red v);
  64. symbolic procedure addd(u,v);
  65. % U is a domain element, V a standard form.
  66. % Value is a standard form for U+V.
  67. if null v then u
  68. else if domainp v then adddm(u,v)
  69. else lt v .+ addd(u,red v);
  70. symbolic procedure adddm(u,v);
  71. % U and V are both non-zero domain elements.
  72. % Value is standard form for U+V.
  73. % The int-equiv-chk is needed to convert say (:MOD: . 0) to NIL.
  74. % A simpler function might therefore be possible and more efficient.
  75. if atom u and atom v
  76. then (if null dmode!* or not flagp(dmode!*,'convert) then !*n2f x
  77. else int!-equiv!-chk apply1(get(dmode!*,'i2d),x))
  78. where x=plus2(u,v)
  79. else dcombine(u,v,'plus);
  80. symbolic procedure domainp u; atom u or atom car u;
  81. symbolic procedure noncomp u;
  82. pairp u and ((if pairp a then noncomfp u else flagp(a,'noncom))
  83. where a=car u);
  84. symbolic procedure multf(u,v);
  85. % U and V are standard forms.
  86. % Value is standard form for U*V.
  87. begin scalar x,y;
  88. a: if null u or null v then return nil
  89. else if u=1 then return v % ONEP
  90. else if v=1 then return u % ONEP
  91. else if domainp u then return multd(u,v)
  92. else if domainp v then return multd(v,u)
  93. else if not(!*exp or ncmp!* or wtl!* or x)
  94. then <<u := mkprod u; v := mkprod v; x := t; go to a>>;
  95. x := mvar u;
  96. y := mvar v;
  97. if noncomfp v and (noncomp x or null !*!*processed)
  98. then return multfnc(u,v)
  99. else if x eq y
  100. then <<% Allow for free variables in rules.
  101. if not fixp ldeg u or not fixp ldeg v
  102. then x := x .** reval list('plus,ldeg u,ldeg v)
  103. else x := mkspm(x,ldeg u+ldeg v);
  104. % The order in the next line is IMPORTANT. See analysis
  105. % by J.H. Davenport et al. for details.
  106. y := addf(multf(red u,v),multf(!*t2f lt u,red v));
  107. return if null x or null(u := multf(lc u,lc v))
  108. then <<!*asymp!* := t; y>>
  109. else if x=1 then addf(u,y)
  110. else if null !*mcd then addf(!*t2f(x .* u),y)
  111. else x .* u .+ y>>
  112. else if ordop(x,y)
  113. then <<x := multf(lc u,v);
  114. y := multf(red u,v);
  115. return if null x then y else lpow u .* x .+ y>>;
  116. x := multf(u,lc v);
  117. y := multf(u,red v);
  118. return if null x then y else lpow v .* x .+ y
  119. end;
  120. symbolic procedure noncomfp u;
  121. % It's possible that ncmp!* would work here.
  122. !*ncmp and noncomfp1 u;
  123. symbolic procedure noncomfp1 u;
  124. not domainp u
  125. and (noncomp mvar u or noncomfp1 lc u or noncomfp1 red u);
  126. symbolic procedure multfnc(u,v);
  127. % Returns canonical product of U and V, with both main vars non-
  128. % commutative.
  129. begin scalar x,y;
  130. x := multf(lc u,!*t2f lt v);
  131. if null x then nil
  132. else if not domainp x and mvar x eq mvar u
  133. then x := addf(if null (y := mkspm(mvar u,ldeg u+ldeg x))
  134. then nil
  135. else if y = 1 then lc x
  136. else !*t2f(y .* lc x),
  137. multf(!*p2f lpow u,red x))
  138. else if noncomp mvar u then x := !*t2f(lpow u .* x)
  139. else x := multf(!*p2f lpow u,x) where !*!*processed=t;
  140. return addf(x,addf(multf(red u,v),multf(!*t2f lt u,red v)))
  141. end;
  142. symbolic procedure multd(u,v);
  143. % U is a domain element, V a standard form.
  144. % Value is standard form for U*V.
  145. if null v then nil
  146. else if v=1 then u % Common enough to be tested.
  147. else if domainp v then multdm(u,v)
  148. else lpow v .* multd(u,lc v) .+ multd(u,red v);
  149. symbolic procedure multdm(u,v);
  150. % U and V are both non-zero domain elements.
  151. % Value is standard form for U*V;
  152. if atom u and atom v
  153. then (lambda x; if null dmode!*
  154. or not flagp(dmode!*,'convert) then x
  155. else % int!-equiv!-chk
  156. apply1(get(dmode!*,'i2d),x))
  157. times2(u,v)
  158. else dcombine(u,v,'times);
  159. smacro procedure multpf(u,v); multf(!*p2f u,v);
  160. symbolic procedure negf u;
  161. if null u then nil
  162. else if domainp u
  163. then !:minus if atom u and flagp(dmode!*,'convert)
  164. then apply1(get(dmode!*,'i2d),u)
  165. else u
  166. else lpow u .* negf lc u .+ negf red u;
  167. symbolic procedure degreef(pol,var);
  168. % Find degree of kernel in standard form pol.
  169. % Note: uniqueness of kernel assumed.
  170. if domainp pol then 0
  171. else if mvar pol eq var then ldeg pol
  172. else max(degreef(lc pol,var),degreef(red pol,var));
  173. put('!*sq,'lengthfn,'!*sqlength);
  174. symbolic procedure !*sqlength u;
  175. (if denr car u=1 then x else x+termsf denr car u)
  176. where x = termsf numr car u;
  177. symbolic procedure terms u;
  178. <<lprim "Please use LENGTH instead"; termsf numr simp!* u>>;
  179. flag('(terms),'opfn);
  180. flag('(terms),'noval);
  181. symbolic procedure termsf u;
  182. % U is a standard form.
  183. % Value is number of terms in U (excluding kernel structure).
  184. begin integer n;
  185. while not domainp u do <<n := n + termsf lc u; u := red u>>;
  186. return if null u then n else n+1
  187. end;
  188. symbolic procedure tmsf u;
  189. % U is a standard form.
  190. % Value is number of terms in U (including kernel structure).
  191. begin integer n; scalar x;
  192. % Integer declaration initializes N to 0.
  193. while not domainp u do
  194. <<n := n+(if sfp(x := mvar u) then tmsf x else 1)+tmsf!* lc u;
  195. if ldeg u neq 1 then if ldeg u=2 then n := n+1 else n := n+2;
  196. u := red u>>; % Previously, if U was non-zero, we used to add
  197. % one more here.
  198. return if null u then n else n+1
  199. end;
  200. symbolic procedure tmsf!* u;
  201. if numberp u and abs fix u=1 then 0 else tmsf u; % Was tmsf u+1.
  202. symbolic procedure tms u; tmsf numr simp!* u;
  203. flag('(tms),'opfn);
  204. flag('(tms),'noval);
  205. % ***** FUNCTIONS FOR WORKING WITH STRUCTURED FORMS *****
  206. fluid '(!*really_off_exp);
  207. symbolic procedure offexpchk u;
  208. % Return structured form for standard quotient u.
  209. % The freevar check is required to correctly evaluate rules like
  210. % for all n let f(a^n-b^n)=c when exp is off and gcd on.
  211. if !*really_off_exp or
  212. (frlis!* and freevarinexptchk numr u or freevarinexptchk denr u)
  213. then u
  214. else canprod(mkprod numr u,mkprod denr u);
  215. symbolic procedure freevarinexptchk u;
  216. not domainp u and(not numberp ldeg u or freevarinexptchk lc u
  217. or freevarinexptchk red u);
  218. symbolic procedure mkprod u;
  219. begin scalar w,x,y,z,!*exp,!*sub2;
  220. if null u or kernlp u then return u;
  221. % First make sure there are no further simplifications.
  222. !*sub2 := t;
  223. x := subs2(u ./ 1);
  224. if denr x neq 1 then return u % We can't do much more here.
  225. else if numr x neq u
  226. then <<u := numr x; if null u or kernlp u then return u>>;
  227. !*exp := t;
  228. w := ckrn u;
  229. u := quotf(u,w);
  230. x := expnd u;
  231. if null x or kernlp x then return multf(w,x);
  232. % After this point, X is not KERNLP.
  233. % The check below for *MCD was suggested by James Davenport.
  234. % Without it, on gcd; off mcd,exp; (x**2+2x+1)/x+1; loops
  235. % forever.
  236. if !*mcd and (!*sqfree or !*factor or !*gcd)
  237. then y := fctrf x
  238. else <<y := ckrn x; x := quotf(x,y); y := list(y,x . 1)>>;
  239. if cdadr y>1 or cddr y
  240. then <<z := car y;
  241. for each j in cdr y do
  242. z := multf(mksp!*(car j,cdr j),z)>>
  243. else if not !*group and tmsf u>tmsf caadr y
  244. then z := multf(mksp!*(caadr y,cdadr y),car y)
  245. else z := mksp!*(u,1);
  246. return multf(w,z)
  247. end;
  248. symbolic procedure expnd u;
  249. if !*really_off_exp then u else
  250. begin scalar !*sub2,v;
  251. u := expnd1 u;
  252. return if !*sub2 and denr(v := subs2f u) = 1 then numr v
  253. else u
  254. end;
  255. symbolic procedure expnd1 u;
  256. if domainp u then u
  257. else addf(if not sfp mvar u or ldeg u<0
  258. then multpf(lpow u,expnd1 lc u)
  259. else multf(exptf(expnd1 mvar u,ldeg u),expnd1 lc u),
  260. expnd1 red u);
  261. symbolic procedure canprod(p,q);
  262. % P and Q are kernel product standard forms, value is P/Q in
  263. % which a top level standard form kernel by itself has been
  264. % unwound.
  265. begin scalar v,w,x,y,z;
  266. if domainp q or red q or (not domainp p and red p)
  267. then return cancel(p ./ q);
  268. % Look for possible cancellations.
  269. while not domainp p or not domainp q do
  270. if sfpf p then <<z := cprod1(mvar p,ldeg p,v,w);
  271. v := car z; w := cdr z; p := lc p>>
  272. else if sfpf q then <<z := cprod1(mvar q,ldeg q,w,v);
  273. w := car z; v := cdr z; q := lc q>>
  274. else if domainp p then <<y := lpow q . y; q := lc q>>
  275. else if domainp q then <<x := lpow p . x; p := lc p>>
  276. else <<x := lpow p . x; y := lpow q . y;
  277. p := lc p; q := lc q>>;
  278. v := reprod(v,reprod(x,p));
  279. w := reprod(w,reprod(y,q));
  280. if minusf w then <<v := negf v; w := negf w>>;
  281. w := cancel(v ./ w);
  282. % Final check for unnecessary structure.
  283. v := numr w;
  284. if not domainp v and null red v and lc v=1
  285. and ldeg v=1 and sfp(x := mvar v)
  286. then v := x;
  287. w := denr w;
  288. if not domainp w and null red w and lc w=1
  289. and ldeg w=1 and sfp(x := mvar w)
  290. then w := x;
  291. return canonsq(v ./ w)
  292. end;
  293. symbolic procedure sfpf u;
  294. not domainp u and sfp mvar u;
  295. symbolic procedure sfp u;
  296. % True if mvar U is a standard form.
  297. not atom u and not atom car u;
  298. symbolic procedure reprod(u,v);
  299. % U is a list of powers, V a standard form.
  300. % Value is product of terms in U with V.
  301. <<while u do <<v := multpf(car u,v); u := cdr u>>; v>>;
  302. symbolic procedure cprod1(p,m,v,w);
  303. % U is a standard form, which occurs in a kernel raised to power M.
  304. % V is a list of powers multiplying P**M, W a list dividing it.
  305. % Value is a dotted pair of lists of powers after all possible
  306. % kernels have been cancelled.
  307. begin scalar z;
  308. z := cprod2(p,m,w,nil);
  309. w := cadr z;
  310. v := append(cddr z,v);
  311. z := cprod2(car z,m,v,t);
  312. v := cadr z;
  313. w := append(cddr z,w);
  314. if car z neq 1 then v := mksp(car z,m) . v;
  315. return v . w
  316. end;
  317. symbolic procedure cprod2(p,m,u,b);
  318. %P and M are as in CPROD1. U is a list of powers. B is true if P**M
  319. %multiplies U, false if it divides.
  320. %Value has three parts: the first is the part of P which does not
  321. %have any common factors with U, the second a list of powers (plus
  322. %U) which multiply U, and the third a list of powers which divide U;
  323. %it is implicit here that the kernel standard forms are positive;
  324. begin scalar n,v,w,y,z;
  325. while u and p neq 1 do
  326. <<if (z := gcdf(p,caar u)) neq 1
  327. then
  328. <<p := quotf(p,z);
  329. y := quotf(caar u,z);
  330. if y neq 1 then v := mksp(y,cdar u) . v;
  331. if b then v := mksp(z,m+cdar u) . v
  332. else if (n := m-cdar u)>0 then w := mksp(z,n) . w
  333. else if n<0 then v := mksp(z,-n) . v>>
  334. else v := car u . v;
  335. u := cdr u>>;
  336. return (p . nconc!*(u,v) . w)
  337. end;
  338. symbolic procedure mkspm(u,p);
  339. %U is a unique kernel, P an integer;
  340. %value is 1 if P=0, NIL if U**P is 0, else standard power of U**P;
  341. % should we add a check for NOT(U EQ K!*) in first line?
  342. if p=0 then 1
  343. else begin scalar x;
  344. if subfg!* and (x:= atsoc(u,asymplis!*)) and cdr x<=p
  345. then return nil;
  346. sub2chk u;
  347. return u .** p
  348. end;
  349. symbolic procedure sub2chk u;
  350. %determines if kernel U is such that a power substitution is
  351. %necessary;
  352. if subfg!*
  353. and(atsoc(u,powlis!*) or not atom u and car u memq '(expt sqrt))
  354. then !*sub2 := t;
  355. % ***** FUNCTIONS FOR DIVIDING STANDARD FORMS *****
  356. symbolic procedure quotsq(u,v);
  357. multsq(u,invsq v);
  358. symbolic procedure quotf!*(u,v);
  359. % We do the rationalizesq step to allow for surd divisors.
  360. if null u then nil
  361. else (if x then x
  362. else (if denr y = 1 then numr y
  363. else errach list("DIVISION FAILED",u,v))
  364. where y=rationalizesq(u ./ v))
  365. where x=quotf(u,v);
  366. symbolic procedure quotf(u,v);
  367. % begin scalar xexp;
  368. % xexp := !*exp;
  369. % !*exp := t;
  370. % u := quotf1(u,v);
  371. % !*exp := xexp;
  372. % return u
  373. % end;
  374. quotf1(u,v) where !*exp = t;
  375. symbolic procedure quotf1(p,q);
  376. % P and Q are standard forms.
  377. % Value is the quotient of P and Q if it exists or NIL.
  378. if null p then nil
  379. else if p=q then 1
  380. else if q=1 then p
  381. else if domainp q then quotfd(p,q)
  382. else if domainp p then nil
  383. else if mvar p eq mvar q
  384. then begin scalar u,v,w,x,xx,y,z,z1; integer n;
  385. a:if idp(u := rank p) or idp(v := rank q) or u<v then return nil;
  386. % The above IDP test is because of the possibility of a free
  387. % variable in the degree position from LET statements.
  388. u := lt!* p;
  389. v := lt!* q;
  390. w := mvar q;
  391. x := quotf1(tc u,tc v);
  392. if null x then return nil;
  393. n := tdeg u-tdeg v;
  394. if n neq 0 then y := w .** n;
  395. % p := addf2zro(p,multf(if n=0 then q
  396. % p := addf(p,multf(negf x,if n=0 then q else multpf(y,q)));
  397. xx := multf(negf x,red q);
  398. % The following expression for p explicitly calculates the
  399. % needed remainder. It has to be this way for non-commuting
  400. % expressions.
  401. p := addf(red p,if n=0 then xx else multpf(y,xx));
  402. % Leading terms of P and Q do not cancel if MCD is off. However,
  403. % there may be a problem with off exp.
  404. if p and (domainp p or not(mvar p eq w)) then return nil
  405. else if n=0 then go to b;
  406. z := aconc!*(z,y .* x);
  407. %provided we have a non-zero power of X, terms
  408. %come out in right order;
  409. if null p then return if z1 then rnconc(z,z1) else z;
  410. go to a;
  411. b: if null p then return rnconc(z,x)
  412. else if !*mcd then return nil
  413. else z1 := x;
  414. go to a
  415. end
  416. else if ordop(mvar p,mvar q) then quotk(p,q)
  417. else nil;
  418. % symbolic procedure addf2zro(p,q);
  419. % <<q := addf(p,q);
  420. % if not dmode!* memq '(!:rd!: !:cr!:)
  421. % or null q or null (p := quotf(q,p)) then q
  422. % else if domainp p then
  423. % if eqcar(p,'!:rd!:)
  424. % and lessp!:(abs!: bfloat round!* p,rd!-tolerance!*)
  425. % or eqcar(p,'!:cr!:)
  426. % and (lessp!:(plus!:(times!:(x,x),times!:(y,y)),cr!-tolerance!*)
  427. % where x=bfloat round!* tagrl p,y=bfloat round!* tagim p)
  428. % then nil else q>>;
  429. symbolic procedure rnconc(u,v);
  430. if null u then v
  431. else if !*ncmp and noncomfp1 u and noncomfp1 v then addf(u,v)
  432. else begin scalar w;
  433. % This is like nconc, but doesn't assume its second argument is a
  434. % list.
  435. w := u;
  436. while cdr w do <<w := cdr w>>;
  437. rplacd(w,v);
  438. return u
  439. end;
  440. symbolic procedure quotfd(p,q);
  441. % P is a standard form, Q a domain element.
  442. % Value is P/Q if exact division is possible, or NIL otherwise.
  443. if p=q then 1
  444. else if flagp(dmode!*,'field) then divd(p,q)
  445. else if domainp p then quotdd(p,q)
  446. else quotk(p,q);
  447. symbolic procedure divd(v,u);
  448. % U is a domain element, V a standard form.
  449. % Value is standard form for V/U.
  450. if null u
  451. then if null v then rerror(poly,1,"0/0 formed")
  452. else rerror(poly,2,"Zero divisor")
  453. else if null v then nil
  454. else if domainp v then divdm(v,u)
  455. else lpow v .* divd(lc v,u) .+ divd(red v,u);
  456. symbolic procedure divdm(v,u);
  457. % U and V are both non-zero domain elements.
  458. % Value is standard form for V/U.
  459. if atom v and atom u
  460. then if remainder(v,u)=0 then v/u
  461. else !:rn2rd mkrn(v,u)
  462. else y % (if null dmode!* then y else int!-equiv!-chk y)
  463. where y=dcombine(v,u,'quotient);
  464. symbolic procedure quotdd(u,v);
  465. % U and V are domain elements. Value is U/V if division is exact,
  466. % NIL otherwise.
  467. begin scalar w;
  468. if atom u then
  469. if atom v then
  470. <<w := divide(u,v); return if cdr w = 0 then car w else nil>>
  471. else if (w := get(car v,'i2d)) then u := apply1(w,u)
  472. else if atom v and (w := get(car u,'i2d)) then v := apply1(w,v);
  473. return dcombine(u,v,'quotient)
  474. end;
  475. symbolic procedure quotk(p,q);
  476. (lambda w;
  477. if w then if null red p then list (lpow p .* w)
  478. else (lambda y;if y then lpow p .* w .+ y else nil)
  479. quotf1(red p,q)
  480. else nil)
  481. quotf1(lc p,q);
  482. symbolic procedure rank p;
  483. %P is a standard form
  484. %Value is the rank of P;
  485. if !*mcd then ldeg p
  486. else begin integer m,n; scalar y;
  487. n := ldeg p;
  488. y := mvar p;
  489. a: m := ldeg p;
  490. if null red p then return n-m;
  491. p := red p;
  492. if degr(p,y)=0 then return if m<0 then if n<0 then -m
  493. else n-m else n;
  494. go to a
  495. end;
  496. symbolic procedure lt!* p;
  497. %Returns true leading term of polynomial P;
  498. if !*mcd or ldeg p>0 then car p
  499. else begin scalar x,y;
  500. x := lt p;
  501. y := mvar p;
  502. a: p := red p;
  503. if null p then return x
  504. else if degr(p,y)=0 then return (y . 0) .* p;
  505. go to a
  506. end;
  507. symbolic procedure remf(u,v);
  508. %returns the remainder of U divided by V;
  509. if null v then rerror(poly,201,"Zero divisor") else cdr qremf(u,v);
  510. put('remainder,'polyfn,'remf);
  511. symbolic procedure qremf(u,v);
  512. % Returns the quotient and remainder of U divided by V.
  513. % Exp cannot be off, otherwise a loop can occur. e.g.,
  514. % qremf('(((x . 1) . -1) . 1),'(((x . 2) . -3) . 4)).
  515. begin integer n; scalar !*exp,x,y,z;
  516. !*exp := t;
  517. if domainp v then return qremd(u,v);
  518. z := list nil; % Final value.
  519. a: if domainp u then return praddf(z,nil . u)
  520. else if mvar u eq mvar v
  521. then if (n := ldeg u-ldeg v)<0 then return praddf(z,nil . u)
  522. else <<x := qremf(lc u,lc v);
  523. y := multpf(lpow u,cdr x);
  524. z := praddf(z,(if n=0 then car x
  525. else multpf(mvar u .** n,car x))
  526. . y);
  527. u := if null car x then red u
  528. else addf(addf(u,multf(if n=0 then v
  529. else multpf(mvar u .** n,v),
  530. negf car x)), negf y);
  531. go to a>>
  532. else if not ordop(mvar u,mvar v)
  533. then return praddf(z,nil . u);
  534. x := qremf(lc u,v);
  535. z := praddf(z,multpf(lpow u,car x) . multpf(lpow u,cdr x));
  536. u := red u;
  537. go to a
  538. end;
  539. symbolic procedure praddf(u,v);
  540. % U and V are dotted pairs of standard forms.
  541. addf(car u,car v) . addf(cdr u,cdr v);
  542. symbolic procedure qremd(u,v);
  543. % Returns a dotted pair of quotient and remainder of form U
  544. % divided by domain element V.
  545. if null u then u . u
  546. else if v=1 then list u
  547. else if flagp(dmode!*,'field) then list multd(!:recip v,u)
  548. else if domainp u then !:divide(u,v)
  549. else begin scalar x;
  550. x := qremf(lc u,v);
  551. return praddf(multpf(lpow u,car x) . multpf(lpow u,cdr x),
  552. qremd(red u,v))
  553. end;
  554. symbolic procedure lqremf(u,v);
  555. %returns a list of coeffs of powers of V in U, constant term first;
  556. begin scalar x,y;
  557. y := list u;
  558. while car(x := qremf(car y,v)) do y := car x . cdr x . cdr y;
  559. return reversip!* y
  560. end;
  561. symbolic procedure minusf u;
  562. %U is a non-zero standard form.
  563. %Value is T if U has a negative leading numerical coeff,
  564. %NIL otherwise;
  565. if null u then nil
  566. else if domainp u
  567. then if atom u then u<0 else apply1(get(car u,'minusp),u)
  568. else minusf lc u;
  569. symbolic procedure absf!* u;
  570. % Returns representation for absolute value of standard form U.
  571. (if domainp u then x else !*p2f mksp(list('abs,prepf x),1))
  572. where x = absf u;
  573. symbolic procedure absf u;
  574. if minusf u then negf u else u;
  575. symbolic procedure canonsq u;
  576. % U is a standard quotient. Value is a standard quotient in which
  577. % the leading power of the denominator has a positive numerical
  578. % coefficient and the denominator is normalized where possible.
  579. if denr u=1 then u
  580. else if null numr u then nil ./ 1
  581. else begin scalar x,y;
  582. % This example shows the following gcd check is needed:
  583. % a:=1+x/2; let x**2=0; a*a;
  584. % Should only be needed when an asymptotic reduction occurs.
  585. if asymplis!* and ((x := gcdf(numr u,denr u)) neq 1)
  586. then u := quotf(numr u,x) ./ quotf(denr u,x);
  587. % Now adjust for a positive leading numerical coeff in denr.
  588. x := lnc denr u;
  589. if x=1 then return u
  590. else if atom x then if minusp x
  591. then <<u := negf numr u ./ negf denr u;
  592. x := -x>>
  593. else nil
  594. else if apply1(get(car x,'minusp),x)
  595. then <<u := negf numr u ./ negf denr u;
  596. x:= apply2(get(car x,'difference),
  597. apply1(get(car x,'i2d),0),
  598. x)>>;
  599. % Now check for a global field mode, a leading domain coeff
  600. % with field properties or "unit" properties so we can adjust
  601. % numr and denr. The tests are done in the following order
  602. % since the other order will give wrong results with some
  603. % polynomials with decimal coefficients in dmode :gi:.
  604. return if not numberp x and (y := get(dmode!*,'unitsfn))
  605. then apply2(y,u,x)
  606. else if flagp(dmode!*,'field)
  607. or not atom x and flagp(car x,'field) then fieldconv(x,u)
  608. else u
  609. end;
  610. symbolic procedure fieldconv(x,u);
  611. % U is a standard quotient and x the leading numerical coefficient
  612. % of the denominator. Returns inverse(x)*numr u/denr u.
  613. % X is a domain, but d may not be; dmode!* or x is field.
  614. begin scalar n,d,y; n := numr u; d := denr u;
  615. if null dmode!* then
  616. <<if not eqcar(x,'!:rn!:)
  617. then if (y := get(car x,'!:rn!:)) and atom y
  618. then x := apply1(y,x)
  619. else if get(car x,'quotient)
  620. then <<x := dcombine(1,x,'quotient);
  621. return multd(x,numr u) ./ multd(x,denr u)>>
  622. else errach list("field conversion",x);
  623. x := (car x) . (cddr x) . cadr x;
  624. return simpgd if domainp d then multd(x,n) ./ 1
  625. else multd(x,n) ./ multd(x,d)>>;
  626. return if domainp d then divd(n,d) ./ 1
  627. else divd(n,x) ./ divd(d,x)
  628. end;
  629. symbolic procedure simpgd u;
  630. if null flagp(dmode!*,'field) then u
  631. else begin scalar x;
  632. if (x := gcdf(numr u,denr u)) neq 1
  633. then u := quotf(numr u,x) ./ quotf(denr u,x);
  634. return u
  635. end;
  636. symbolic procedure lnc u;
  637. % U is a standard form. Value is the leading numerical coefficient.
  638. if null u then 0
  639. else if domainp u then u
  640. else lnc lc u;
  641. symbolic procedure invsq u;
  642. begin
  643. if null numr u then rerror(poly,3,"Zero divisor");
  644. u := revpr u;
  645. if !*rationalize then u := gcdchk u;
  646. % Since result may not be in lowest terms.
  647. return canonsq u
  648. end;
  649. symbolic procedure gcdchk u;
  650. % Makes sure standard quotient u is in lowest terms.
  651. (if x neq 1 then quotf(numr u,x) ./ quotf(denr u,x) else u)
  652. where x = gcdf(numr u,denr u);
  653. endmodule;
  654. end;