modlineq.red 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. module modlineq;
  2. % Author: James H. Davenport.
  3. fluid '(!*tra !*trmin current!-modulus sqrts!-mod!-prime);
  4. global '(list!-of!-medium!-primes sqrts!-mod!-8);
  5. exports check!-lineq;
  6. list!-of!-medium!-primes:='(101 103 107 109);
  7. sqrts!-mod!-8:=mkvect 7;
  8. putv(sqrts!-mod!-8,0,t);
  9. putv(sqrts!-mod!-8,1,t);
  10. putv(sqrts!-mod!-8,4,t);
  11. symbolic procedure modp!-nth!-root(m,n,p);
  12. begin
  13. scalar j,p2;
  14. p2:=p/2;
  15. for i:=-p2 step 1 until p2 do
  16. if modular!-expt(i,n) iequal m
  17. then << j:=i; i:=p2 >>;
  18. return j
  19. end;
  20. symbolic procedure modp!-sqrt(n,p);
  21. begin
  22. scalar p2,s,tt;
  23. p2:=p/2;
  24. if n < 0
  25. then n:=n+p;
  26. for i:=0:p2 do begin
  27. tt:=n+p*i;
  28. if null getv(sqrts!-mod!-8,iremainder(tt,8))
  29. then return;
  30. % mod 8 test for perfect squares.
  31. if (iadd1 iremainder(tt,5)) > 2
  32. then return;
  33. % squares are -1,0,1 mod 5.
  34. s:=int!-sqrt tt;
  35. if fixp s then <<
  36. p2:=0;
  37. return >>
  38. end;
  39. if (not fixp s) or null s
  40. then return nil
  41. else return s
  42. end;
  43. symbolic procedure check!-lineq(m,rightside);
  44. begin
  45. scalar vlist,n1,n2,u,primelist,m1,v,modp!-subs,atoms;
  46. n1:=upbv m;
  47. for i:=0:n1 do <<
  48. u:=getv(m,i);
  49. if u
  50. then for j:=0:(n2:=upbv u) do
  51. vlist:=varsinsq(getv(u,j),vlist) >>;
  52. u:=vlist;
  53. while u do <<
  54. v:=car u;
  55. u:=cdr u;
  56. if atom v
  57. then atoms:=v.atoms
  58. else if (car v eq 'sqrt) or (car v eq 'expt)
  59. then for each w in varsinsf(!*q2f simp argof v,nil) do
  60. if not (w member vlist)
  61. then <<
  62. u:=w.u;
  63. vlist:=w.vlist >>
  64. else nil
  65. else interr "Unexpected item" >>;
  66. if sqrts!-mod!-prime and
  67. subsetp(vlist,for each u in cdr sqrts!-mod!-prime
  68. collect car u)
  69. then go to end!-of!-loop;
  70. vlist:=setdiff(vlist,atoms);
  71. u:=nil;
  72. for each v in vlist do
  73. if car v neq 'sqrt
  74. then u:=v.u;
  75. vlist:=nconc(u,sortsqrts(setdiff(vlist,u),nil));
  76. % NIL is the variable to measure nesting on:
  77. % therefore all nesting is being caught.
  78. primelist:=list!-of!-medium!-primes;
  79. set!-modulus car primelist;
  80. atoms:=for each u in atoms collect
  81. u . modular!-number random car primelist;
  82. goto try!-prime;
  83. next!-prime:
  84. primelist:=cdr primelist;
  85. if null primelist and !*tra
  86. then printc "Ran out of primes in check!-lineq";
  87. if null primelist
  88. then return t;
  89. set!-modulus car primelist;
  90. try!-prime:
  91. modp!-subs:=atoms;
  92. v:=vlist;
  93. loop:
  94. if null v
  95. then go to end!-of!-loop;
  96. u:=modp!-subst(simp argof car v,modp!-subs);
  97. if caar v eq 'sqrt
  98. then u:=modp!-sqrt(u,car primelist)
  99. else if caar v eq 'expt
  100. then u:=modp!-nth!-root(modular!-expt(u,cadr caddr car v),
  101. caddr caddr car v,car primelist)
  102. else interr "Unexpected item";
  103. if null u
  104. then go to next!-prime;
  105. modp!-subs:=(car v . u) . modp!-subs;
  106. v:=cdr v;
  107. go to loop;
  108. end!-of!-loop:
  109. if null primelist
  110. then <<
  111. setmod(car sqrts!-mod!-prime);
  112. modp!-subs:=cdr sqrts!-mod!-prime >>
  113. else sqrts!-mod!-prime:=(car primelist).modp!-subs;
  114. m1:=mkvect n1;
  115. for i:=0:n1 do begin
  116. u:=getv(m,i);
  117. if null u
  118. then return;
  119. putv(m1,i,v:=mkvect n2);
  120. for j:=0:n2 do
  121. putv(v,j,modp!-subst(getv(u,j),modp!-subs))
  122. end;
  123. v:=mkvect n1;
  124. for i:=0:n1 do
  125. putv(v,i,modp!-subst(getv(rightside,i),modp!-subs));
  126. u:=mod!-jhdsolve(m1,v);
  127. if (u eq 'failed) and (!*tra or !*trmin)
  128. then <<
  129. princ "Proved insoluble mod ";
  130. printc car sqrts!-mod!-prime >>;
  131. return u
  132. end;
  133. symbolic procedure varsinsq(sq,vl);
  134. varsinsf(numr sq,varsinsf(denr sq,vl));
  135. symbolic procedure modp!-subst(sq,slist);
  136. modular!-quotient(modp!-subf(numr sq,slist),
  137. modp!-subf(denr sq,slist));
  138. symbolic procedure modp!-subf(sf,slist);
  139. if atom sf
  140. then if null sf
  141. then 0
  142. else modular!-number sf
  143. else begin
  144. scalar u;
  145. u:=assoc(mvar sf,slist);
  146. if null u
  147. then interr "Unexpected variable";
  148. return modular!-plus(modular!-times(modular!-expt(cdr u,ldeg sf),
  149. modp!-subf(lc sf,slist)),
  150. modp!-subf(red sf,slist))
  151. end;
  152. symbolic procedure mod!-jhdsolve(m,rightside);
  153. % Returns answer to m.answer=rightside.
  154. % Matrix m not necessarily square.
  155. begin
  156. scalar ii,n1,n2,ans,u,row,swapflg,swaps;
  157. % The SWAPFLG is true if we have changed the order of the
  158. % columns and need later to invert this via SWAPS.
  159. n1:=upbv m;
  160. for i:=0:n1 do
  161. if (u:=getv(m,i))
  162. then (n2:=upbv u);
  163. swaps:=mkvect n2;
  164. for i:=0:n2 do
  165. putv(swaps,i,n2-i);
  166. % We have the SWAPS vector, which should be a vector of indices,
  167. % arranged like this because VECSORT sorts in decreasing order.
  168. for i:=0:isub1 n1 do begin
  169. scalar k,v,pivot;
  170. tryagain:
  171. row:=getv(m,i);
  172. if null row
  173. then go to interchange;
  174. % look for a pivot in row.
  175. k:=-1;
  176. for j:=0:n2 do
  177. if (pivot:=getv(row,j)) neq 0
  178. then <<
  179. k:=j;
  180. j:=n2 >>;
  181. if k neq -1
  182. then goto newrow;
  183. if getv(rightside,i) neq 0
  184. then <<
  185. m:='failed;
  186. i:=sub1 n1; %Force end of loop.
  187. go to finished >>;
  188. interchange:
  189. % now interchange i and last element.
  190. swap(m,i,n1);
  191. swap(rightside,i,n1);
  192. n1:=isub1 n1;
  193. if i iequal n1
  194. then goto finished
  195. else goto tryagain;
  196. newrow:
  197. if i neq k
  198. then <<
  199. swapflg:=t;
  200. swap(swaps,i,k);
  201. % record what we have done.
  202. for l:=0:n1 do
  203. swap(getv(m,l),i,k) >>;
  204. % place pivot on diagonal.
  205. pivot:=modular!-minus modular!-reciprocal pivot;
  206. for j:=iadd1 i:n1 do begin
  207. u:=getv(m,j);
  208. if null u
  209. then return;
  210. v:=modular!-times(getv(u,i),pivot);
  211. if v neq 0 then <<
  212. putv(rightside,j,
  213. modular!-plus(getv(rightside,j),
  214. modular!-times(v,getv(rightside,i))));
  215. for l:=0:n2 do
  216. putv(u,l,
  217. modular!-plus(getv(u,l),
  218. modular!-times(v,getv(row,l)))) >>
  219. end;
  220. finished:
  221. end;
  222. if m eq 'failed
  223. then go to failed;
  224. % Equations were inconsistent.
  225. while null (row:=getv(m,n1)) do
  226. n1:=isub1 n1;
  227. u:=nil;
  228. for i:=0:n2 do
  229. if getv(row,i) neq 0 then u:='t;
  230. if null u
  231. then if getv(rightside,n1) neq 0
  232. then go to failed
  233. else n1:=isub1 n1;
  234. % Deals with a last equation which is all zero.
  235. if n1 > n2
  236. then go to failed;
  237. % Too many equations to satisfy.
  238. ans:=mkvect n2;
  239. for i:=0:n2 do
  240. putv(ans,i,0);
  241. % now to do the back-substitution.
  242. % Note that the system is not necessarily square.
  243. ii:=n2;
  244. for i:=n1 step -1 until 0 do begin
  245. row:=getv(m,i);
  246. while getv(row,ii) = 0 do ii:=isub1 ii;
  247. if null row
  248. then return;
  249. u:=getv(rightside,i);
  250. for j:=iadd1 ii:n2 do
  251. u:=modular!-plus(u,
  252. modular!-times(getv(row,j),modular!-minus getv(ans,j)));
  253. putv(ans,ii,modular!-times(u,modular!-reciprocal getv(row,ii)));
  254. ii:=isub1 ii;
  255. end;
  256. if swapflg
  257. then vecsort(swaps,list ans);
  258. return ans;
  259. failed:
  260. if !*tra
  261. then printc "Unable to force correct zeroes";
  262. return 'failed
  263. end;
  264. endmodule;
  265. end;