gint.red 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. module gint; % Support for gaussian integers (complex numbers).
  2. % Author: Eberhard Schruefer.
  3. global '(domainlist!*);
  4. fluid '(!*complex !*gcd);
  5. switch complex;
  6. domainlist!* := union('(!:gi!:),domainlist!*);
  7. symbolic procedure setcmpxmode(u,bool);
  8. % Sets polynomial domain mode in complex case.
  9. begin scalar x,y;
  10. x := get(u,'tag);
  11. if u eq 'complex
  12. then if null dmode!*
  13. then return if null bool then nil
  14. else <<put('i,'idvalfn,'mkdgi);
  15. setdmode1('complex,bool)>>
  16. else if null bool
  17. then return if null !*complex then nil
  18. else if get(dmode!*,'dname) eq 'complex
  19. then <<remprop('i,'idvalfn);
  20. setdmode1('complex,nil)>>
  21. else <<remprop('i,'idvalfn);
  22. setdmode1(get(get(dmode!*,'realtype),'dname),
  23. t)>>
  24. else if dmode!* eq '!:gi!: or get(dmode!*,'realtype)
  25. then return nil
  26. else if not (y := get(dmode!*,'cmpxtype))
  27. then dmoderr(dmode!*,x)
  28. else <<put('i,'idvalfn,get(y,'ivalue));
  29. return setdmode1(get(y,'dname),bool)>>
  30. else if null bool then
  31. if u eq (y := get(get(dmode!*,'realtype),'dname)) then
  32. <<put('i,'idvalfn,'mkdgi); return setdmode1('complex,t)>>
  33. else if null y then return nil
  34. else offmoderr(u,y)
  35. else <<u := get(u,'tag);
  36. y := get(u,'cmpxtype);
  37. if null y then dmoderr(u,'!:gi!:);
  38. put('i,'idvalfn,get(y,'ivalue));
  39. return setdmode1(get(y,'dname),bool)>>
  40. end;
  41. % Used by gcdk.
  42. symbolic procedure intgcdd(u,v);
  43. if null u then v
  44. else if atom u then
  45. if atom v then gcdn(u,v) else gcdn(cadr v,gcdn(cddr v,u))
  46. else if atom v then intgcdd(v,u)
  47. else intgcdd(cadr u,intgcdd(cddr u,v));
  48. put('complex,'tag,'!:gi!:);
  49. put('!:gi!:,'dname,'complex);
  50. put('!:gi!:,'i2d,'!*i2gi);
  51. put('!:gi!:,'minusp,'giminusp!:);
  52. put('!:gi!:,'zerop,'gizerop!:);
  53. put('!:gi!:,'onep,'gionep!:);
  54. put('!:gi!:,'plus,'giplus!:);
  55. put('!:gi!:,'difference,'gidifference!:);
  56. put('!:gi!:,'times,'gitimes!:);
  57. put('!:gi!:,'quotient,'giquotient!:);
  58. put('!:gi!:,'divide,'gidivide!:);
  59. put('!:gi!:,'gcd,'gigcd!:);
  60. put('!:gi!:,'factorfn,'gifactor!:);
  61. % put('!:gi!:,'rationalizefn,'girationalize!:);
  62. put('!:gi!:,'prepfn,'giprep!:);
  63. put('!:gi!:,'intequivfn,'gintequiv!:);
  64. put('!:gi!:,'specprn,'giprn!:);
  65. put('!:gi!:,'prifn,'giprn!:);
  66. put('!:gi!:,'cmpxfn,'mkgi);
  67. put('!:gi!:,'unitsfn,'!:gi!:unitconv);
  68. symbolic procedure !:gi!:unitconv(u,v);
  69. unitconv(u,v,get('!:gi!:,'units));
  70. put('!:gi!:,'units,'(((!:gi!: 0 . 1) . (!:gi!: 0 . -1))
  71. ((!:gi!: 0 . -1) . (!:gi!: 0 . 1))));
  72. symbolic procedure unitconv(u,v,w);
  73. begin scalar z;
  74. a: if null w then return u;
  75. z := quotf1(v,caar w);
  76. if null z or not fixp z then <<w := cdr w; go to a>>;
  77. z := multf(denr u,cdar w);
  78. w := multf(numr u,cdar w);
  79. if minusf z then <<w := negf w; z := negf z>>;
  80. return w ./ z
  81. end;
  82. symbolic procedure !*i2gi u; '!:gi!: . (u . 0);
  83. symbolic procedure giminusp!: u;
  84. %*** this is rather a test for u being in a canonical form! ***;
  85. if cadr u = 0 then minusp cddr u else minusp cadr u;
  86. symbolic procedure gizerop!: u;
  87. cadr u = 0 and cddr u = 0;
  88. symbolic procedure gionep!: u;
  89. cadr u=1 and cddr u=0;
  90. symbolic procedure gintequiv!: u;
  91. if cddr u=0 then cadr u else nil;
  92. symbolic procedure mkdgi u;
  93. ('!:gi!: . (0 . 1)) ./ 1;
  94. symbolic procedure mkgi(re,im);
  95. '!:gi!: . (re . im);
  96. symbolic procedure giplus!:(u,v);
  97. mkgi(cadr u+cadr v,cddr u+cddr v);
  98. symbolic procedure gidifference!:(u,v);
  99. mkgi(cadr u-cadr v,cddr u-cddr v);
  100. symbolic procedure gitimes!:(u,v);
  101. (lambda r1,i1,r2,i2;
  102. mkgi(r1*r2-i1*i2,r1*i2+r2*i1))
  103. (cadr u,cddr u,cadr v,cddr v);
  104. symbolic procedure giquotient!:(u,v);
  105. begin integer r1,i1,r2,i2,d; scalar rr,ii;
  106. r1 := cadr u; i1 := cddr u;
  107. r2 := cadr v; i2 := cddr v;
  108. d := r2*r2+i2*i2;
  109. rr := divide(r1*r2+i1*i2,d);
  110. ii := divide(i1*r2-i2*r1,d);
  111. return if cdr ii=0 and cdr rr=0 then mkgi(car rr,car ii)
  112. else '!:gi!: . (0 . 0)
  113. end;
  114. symbolic procedure gidivide!:(u,v);
  115. begin integer r1,i1,r2,i2,d,rr,ir,rq,iq;
  116. r1 := cadr u; i1 := cddr u;
  117. r2 := cadr v; i2 := cddr v;
  118. d := r2*r2+i2*i2;
  119. rq := r1*r2+i1*i2;
  120. iq := i1*r2-i2*r1;
  121. rq := car divide(2*rq+if rq<0 then -d else d,2*d);
  122. iq := car divide(2*iq+if iq<0 then -d else d,2*d);
  123. rr := r1-(rq*r2-iq*i2);
  124. ir := i1-(iq*r2+rq*i2);
  125. return mkgi(rq,iq) . mkgi(rr,ir)
  126. end;
  127. symbolic procedure giremainder(u,v);
  128. begin integer r1,i1,r2,i2,d,rr,ir,rq,iq;
  129. r1 := cadr u; i1 := cddr u;
  130. r2 := cadr v; i2 := cddr v;
  131. d := r2*r2+i2*i2;
  132. rq := r1*r2+i1*i2;
  133. iq := i1*r2-i2*r1;
  134. rq := car divide(2*rq+if rq<0 then -d else d,2*d);
  135. iq := car divide(2*iq+if iq<0 then -d else d,2*d);
  136. rr := r1-(rq*r2-iq*i2);
  137. ir := i1-(iq*r2+rq*i2);
  138. return '!:gi!: . (rr . ir)
  139. end;
  140. symbolic procedure gigcd!:(u,v);
  141. % Straightforward Euclidean algorithm.
  142. if gizerop!: v then fqa u else gigcd!:(v,giremainder(u,v));
  143. symbolic procedure fqa u;
  144. %calculates the unique first-quadrant associate of u;
  145. if cddr u=0 then abs cadr u
  146. else if cadr u=0 then '!:gi!: . (abs cddr u . 0)
  147. else if (cadr u*cddr u)>0 then
  148. '!:gi!: . (abs cadr u . abs cddr u)
  149. else '!:gi!: . (abs cddr u . abs cadr u);
  150. symbolic procedure gifactor!: u;
  151. % Trager's modified version of Van der Waerdens algorithm.
  152. begin scalar x,y,norm,aftrs,ftrs,mvu,dmode!*,!*exp,w,z,l,bool;
  153. integer s;
  154. !*exp := t;
  155. if realp u
  156. then u := cdr factorf u
  157. else u := list(u . 1);
  158. w := 1;
  159. for each f in u do begin
  160. u := car f;
  161. dmode!* := '!:gi!:;
  162. mvu := power!-sort powers u;
  163. bool := contains!-oddpower mvu;
  164. if realp u and bool
  165. then <<u := normalize!-lcgi u;
  166. w := multd(car u,w);
  167. aftrs := (cdr u . 1) . aftrs;
  168. return>>;
  169. mvu := caar mvu;
  170. y := u;
  171. go to b;
  172. a: l := list(mvu . prepf addf(!*k2f mvu,multd(s,!*k2f 'i)));
  173. u := numr subf1(y,l);
  174. b: if realp u
  175. then if bool
  176. then <<y := normalize!-lcgi y;
  177. w := multd(car y,w);
  178. aftrs := (cdr y . 1) . aftrs;
  179. return>>
  180. else <<s := s-1; go to a>>;
  181. norm := multf(u,conjgd u);
  182. if not sqfrp norm then <<s := s-1; go to a>>;
  183. dmode!* := nil;
  184. ftrs := factorf norm;
  185. dmode!* := '!:gi!:;
  186. if null cddr ftrs then <<y := normalize!-lcgi y;
  187. w := multd(car y,w);
  188. aftrs := (cdr y . 1) . aftrs;
  189. return>>;
  190. w := car ftrs;
  191. l := if s=0 then nil
  192. else list(mvu . prepf addf(!*k2f mvu,
  193. negf multd(s,!*k2f 'i)));
  194. for each j in cdr ftrs do
  195. <<x := gcdf!*(car j,u);
  196. u := quotf!*(u,x);
  197. z := if l then numr subf1(x,l) else x;
  198. z := normalize!-lcgi z;
  199. w := multd(car z,w);
  200. aftrs := (cdr z . 1) . aftrs>>;
  201. w := multf(u,w) end;
  202. return w . aftrs
  203. end;
  204. symbolic procedure normalize!-lcgi u;
  205. % Normalize lnc by using units as canonsq would do it.
  206. begin scalar l,x,y;
  207. l := lnc u;
  208. if numberp l then return if minusp l then (-1) . negf u
  209. else 1 . u;
  210. x := get('!:gi!:,'units);
  211. a: if null x then return 1 . u;
  212. y := quotf1(l,caar x);
  213. if null y or null fixp y then <<x := cdr x; go to a>>;
  214. u := multd(cdar x,u);
  215. return if minusf u then negf caar x . negf u
  216. else caar x . u
  217. end;
  218. symbolic procedure contains!-oddpower u;
  219. if null u then nil
  220. else if evenp cdar u then contains!-oddpower cdr u
  221. else t;
  222. symbolic procedure power!-sort u;
  223. begin scalar x,y;
  224. while u do
  225. <<x := maxdeg(cdr u,car u);
  226. u := delallasc(car x,u);
  227. y := x . y>>;
  228. return y
  229. end;
  230. symbolic procedure sqfrp u;
  231. % Square free test for poly u over the integers.
  232. % It works best with ezgcd on.
  233. begin scalar !*ezgcd, dmode!*;
  234. % Make sure ezgcd loaded.
  235. if null getd 'ezgcdf1 then load_package ezgcd;
  236. !*ezgcd := t;
  237. return domainp gcdf!*(u,diff(u,mvar u))
  238. end;
  239. symbolic procedure realp u;
  240. if domainp u
  241. then atom u
  242. or not get(car u,'cmpxfn)
  243. or cddr u = cddr apply1(get(car u,'i2d),1)
  244. else realp lc u and realp red u;
  245. symbolic procedure fd2f u;
  246. if atom u then u
  247. else if car u eq '!:gi!:
  248. then addf(!*n2f cadr u,multf(!*k2f 'i,!*n2f cddr u))
  249. else addf(multf(!*p2f lpow u,fd2f lc u),fd2f red u);
  250. % symbolic procedure giprep!: u; %giprep1 cdr u;
  251. % prepsq!* addsq(!*n2f cadr u ./ 1,
  252. % multsq(!*n2f cddr u ./ 1, !*k2q 'i));
  253. % symbolic procedure giprep1 u; %not used now;
  254. % if cdr u=0 then car u
  255. % else if car u=0 then retimes list(cdr u,'i)
  256. % else begin scalar gn;
  257. % gn := gcdn(car u,cdr u);
  258. % return retimes list(gn,
  259. % replus list(car u/gn,retimes list(cdr u/gn,'i)))
  260. % end;
  261. symbolic procedure giprep!: u;
  262. <<if im=0 then rl else if rl=0 then giprim im
  263. else if im<0 then list('difference,rl,giprim(minus im))
  264. else list('plus,rl,giprim im)>>
  265. where rl=cadr u,im=cddr u;
  266. symbolic procedure giprim im; if im=1 then 'i else list('times,im,'i);
  267. symbolic procedure giprn!: v;
  268. (lambda u;
  269. if atom u or (car u eq 'times) then maprin u
  270. else <<prin2!* "("; maprin u; prin2!* ")" >>) giprep!: v;
  271. % symbolic procedure girationalize!: u;
  272. % %Rationalizes standard quotient u over the gaussian integers.
  273. % begin scalar x,y,z;
  274. % y := denr u;
  275. % z := conjgd y;
  276. % if y=z then return u;
  277. % x := multf(numr u,z);
  278. % y := multf(y,z);
  279. % return x ./ y
  280. % end;
  281. symbolic procedure girationalize!: u;
  282. % Rationalizes standard quotient u over the gaussian integers.
  283. begin scalar y,z,!*gcd;
  284. !*gcd := t;
  285. if y=(z := conjgd(y := denr u)) then return u;
  286. % Remove from z any real polynomial factors of y and z.
  287. z := quotf(z,quotf(
  288. gcdf(addf(y,z),multf(addf(z,negf y),'!:gi!: . (0 . 1))),2));
  289. % The following subs2 can undo the above if !*match is non-NIL.
  290. % return subs2 gigcdsq(multf(numr u,z),multf(y,z))
  291. return gigcdsq(multf(numr u,z),multf(y,z))
  292. end;
  293. symbolic procedure gigcdsq(x,y); % remove integer common factor.
  294. <<if x then
  295. (<<if d neq 1 and (d := giintgcd(x,d)) neq 1 then
  296. <<x := quotf(x,d); y := quotf(y,d)>> >>
  297. where d=giintgcd(y,0)); x ./ y >>;
  298. symbolic procedure giintgcd(u,d);
  299. if d=1 then 1 else if null u then d else if atom u then gcdn(u,d)
  300. else if eqcar(u,'!:gi!:) then gcdn(cadr u,gcdn(cddr u,d))
  301. else giintgcd(lc u,giintgcd(red u,d));
  302. symbolic procedure conjgd u;
  303. begin scalar x;
  304. return if atom u then u
  305. else if domainp u and (x := get(car u,'cmpxfn))
  306. then
  307. apply2(x,cadr u,
  308. if numberp cddr u then -cddr u
  309. % Allow for tagged parts of complex object.
  310. else if domainp cddr u and not numberp caddr u
  311. then !:minus cddr u
  312. else cdr !:minus (get(car u,'realtype).cddr u))
  313. else if domainp u then u % Should be a real number now.
  314. else addf(multpf(lpow u,conjgd lc u),conjgd red u)
  315. end;
  316. initdmode 'complex;
  317. endmodule;
  318. end;