modsolve.red 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. module modsolve; % Solve modular.
  2. % Author: Herbert Melenk <melenk@zib-berlin.dbp.de>
  3. % Algebraic interface: m_solve(eqn/eqnlist [,variables]).
  4. % Some routines from solve and factor(modpoly) are needed.
  5. fluid '(!*trnonlnr );
  6. load!-package 'solve;
  7. load!-package 'factor;
  8. put('m_solve,'psopfn,'msolve);
  9. symbolic procedure msolve(u);
  10. begin scalar s,s1,v,v1,w;
  11. s:=reval car u;
  12. s:=if eqcar(s,'list) then cdr s else {s};
  13. if cdr u then
  14. <<v:= reval cadr u;
  15. v:=if eqcar(v,'list) then cdr v else {v};
  16. >>;
  17. % test, collect variables.
  18. s1:=for each q in s collect
  19. <<if eqcar(q,'equal) then q:='difference.cdr q;
  20. w:=numr simp q ./ 1; v1:=union(v1,solvevars{w});
  21. numr w>>;
  22. if null v then v:=v1;
  23. return msolve!-result
  24. if length s1 = 1
  25. then msolve!-poly(car s1,v)
  26. else msolve!-psys(s1,v);
  27. end;
  28. symbolic procedure msolve!-result u;
  29. if u='failed then u else
  30. 'list . for each v in u collect
  31. 'list . for each w in v collect {'equal,car w,cdr w};
  32. symbolic procedure msolvesys(s1,v,tg);
  33. % Interface for the Solve package.
  34. begin scalar w,fail;
  35. if null cdr s1 then
  36. <<w:= msolve!-poly(car s1,v); goto done>>;
  37. % Reject parametric modular equation system.
  38. for each p in s1 do
  39. for each x in kernels p do
  40. if not member(x,v) then fail:=t;
  41. if fail then
  42. << if !*trnonlnr
  43. then lprim "cannot solve parametric modular system";
  44. go to failed>>;
  45. w:= msolve!-psys(s1,v);
  46. if w='failed then go to failed;
  47. done:
  48. w:=for each q in w collect
  49. {for each r in q collect simp cdr r,
  50. for each r in q collect car r, 1};
  51. return if tg then t.w else w;
  52. failed:
  53. return if tg then '(failed) else 'failed;
  54. end;
  55. symbolic procedure msolve!-poly1(f,x);
  56. % polynomial f(x);
  57. begin scalar w,l;
  58. if ldeg f = 1 then
  59. <<w:=safe!-modrecip lc f;
  60. erfg!*:=nil;
  61. if null w then go to enum;
  62. w:=moduntag multf(w,negf red f);
  63. if w and (w< 0 or w>current!-modulus)
  64. then w:=general!-modular!-number w;
  65. w:={w};
  66. go to done;
  67. >>;
  68. enum:
  69. l := lowestdeg(f,x,0);
  70. if l>0 then f:=quotf(f,numr simp {'expt,x,l});
  71. f:=general!-reduce!-mod!-p moduntag f;
  72. w:=for i:=1:current!-modulus -1 join
  73. if null general!-evaluate!-mod!-p(f,x,i) then {i};
  74. if l>0 then w:=append(w,{nil});
  75. done:
  76. return for each q in w collect {x.prepf q};
  77. end;
  78. symbolic procedure msolve!-poly(f,l);
  79. % Solve one polynomial wrt several variables.
  80. begin scalar x,vl;
  81. vl := kernels f;
  82. for each x in l do
  83. <<if not member(x,vl) then l:=delete(x,l);
  84. vl := delete(x,vl)>>;
  85. if null l then return nil;
  86. if vl then return msolve!-polya(f,l);
  87. return msolve!-polyn(f,l);
  88. end;
  89. symbolic procedure msolve!-polyn(f,l);
  90. ( if null cdr l then msolve!-poly1(f,car l) else
  91. for i:=0: current!-modulus -1 join
  92. for each s in msolve!-polyn(numr subf(f,{x.i}),cdr l)
  93. collect (x.i).s) where x=car l;
  94. symbolic procedure msolve!-polya(f,l);
  95. % F is a polynomial with variables in l and at least one more
  96. % formal parameter. F can be solved only if f is linear in one of the
  97. % variables with an invertible coefficient. Otherwise we must return
  98. % a root-of expression.
  99. begin scalar x,c,w;
  100. for each y in l do if null x then
  101. if 1=ldeg ((w:=reorder f) where kord!* = {y}) then x:=y;
  102. if null x then goto none;
  103. c:=lc w; w:=red w;
  104. if not domainp c then goto none;
  105. c:=safe!-modrecip c;
  106. if null c then goto none;
  107. return {{x.prepf multf(negf w,c)}};
  108. none:
  109. return {{car l. mk!*sq caaar mkrootsof(f./1,car l,1)}};
  110. end;
  111. symbolic procedure msolve!-psys(s,v);
  112. % Solve system s for variables v. S has no additional free parameters.
  113. begin scalar b,o,z,w;
  114. if current!-modulus * length s >1000
  115. and primep current!-modulus then
  116. << % Domain is a field and big problem - compute a GB first.
  117. load!-package 'groebner; load!-package 'groebnr2;
  118. o:=apply1('torder,{'list.v,'lex});
  119. b:=groebnereval{'list.for each p in s collect prepf p};
  120. z:=gzerodimeval {b};
  121. % The reverse basis for increasing variable number.
  122. s:=reversip for each p in cdr b collect numr simp p;
  123. apply1('torder,cdr o);
  124. >>
  125. else
  126. << % Rearrange system for increasing variable number.
  127. w:=for each p in s collect
  128. length(for each x in v join if smemq(x,p) then {x}).p;
  129. w:= for each p in sort(w,'lesspcar) collect cdr p
  130. >>;
  131. return msolve!-psys1(s,v);
  132. end;
  133. symbolic procedure msolve!-psys1(s,v);
  134. % Solve system by successive substitution.
  135. begin scalar w,w1,f,f1;
  136. w:={nil};
  137. for each f in s do
  138. <<w1:=nil;
  139. for each s in w do
  140. <<f1:=general!-reduce!-mod!-p moduntag numr subf(f,s);
  141. if null f1 then w1:=s.w1
  142. else if domainp f1 then nil
  143. else for each ns in msolve!-poly(f1,v) do
  144. w1:=append(s,ns) . w1
  145. >>;
  146. w:=w1;
  147. >>;
  148. return w;
  149. end;
  150. endmodule;
  151. end;