edspatch.red 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. module edspatch;
  2. % Various patches for other parts of Reduce.
  3. % Author: David Hartley
  4. fluid '(!*edsverbose !*edsdebug !*arbvars !*varopt !*groebopt
  5. !*solveinconsistent depl!*);
  6. %%% General changes
  7. % Extend MAP/SELECT to other structures than list/matrix
  8. symbolic procedure map!-eval1(o,q,fcn1,fcn2);
  9. % o structure to be mapped.
  10. % q map expression (univariate function).
  11. % fcn1 function for evaluating members of o.
  12. % fcn2 function computing results (e.g. aeval).
  13. map!-apply(map!-function(q,fcn1,fcn2),o);
  14. symbolic procedure map!-function(q,fcn1,fcn2);
  15. begin scalar v,w;
  16. v := '!&!&x;
  17. if idp q
  18. and (get(q,'simpfn) or get(q,'number!-of!-args)=1)
  19. then <<w:=v; q:={q,v}>>
  20. else if eqcar(q,'replaceby) then
  21. <<w:=cadr q; q:=caddr q>>
  22. else
  23. <<w:=map!-frvarsof(q,nil);
  24. if null w then rederr "map/select: no free variable found" else
  25. if cdr w then rederr "map/select: free variable ambiguous";
  26. w := car w;
  27. >>;
  28. if eqcar(w,'!~) then w:=cadr w;
  29. q := sublis({w.v,{'!~,w}.v},q);
  30. return {'lambda,{'w},
  31. {'map!-eval2,'w,mkquote v,mkquote q,mkquote fcn1,mkquote fcn2}};
  32. end;
  33. symbolic procedure map!-apply(f,o);
  34. if atom o then apply1(f,o)
  35. else (if m then apply2(m,f,o)
  36. else car o . for each w in cdr o collect apply1(f,w))
  37. where m = get(car o,'mapfn);
  38. symbolic procedure mapmat(f,o);
  39. 'mat . for each row in cdr o collect
  40. for each w in row collect
  41. apply1(f,w);
  42. put('mat,'mapfn,'mapmat);
  43. %%% EXCALC modifications
  44. global '(indxl!*);
  45. fluid '(kord!*);
  46. % Remove covariant flag from indexed 0-forms.
  47. % Add a subfunc to indexed forms.
  48. if not getd 'excalcputform then copyd('excalcputform,'putform);
  49. symbolic procedure putform(u,v);
  50. begin
  51. excalcputform(u,v);
  52. if not atom u then
  53. << put(car u,'subfunc,'(lambda (a b) b));
  54. remflag({car u},'covariant) >>;
  55. end;
  56. % Have to update ndepends to REDUCE3.6 depends.
  57. symbolic procedure ndepends(u,v);
  58. if null u or numberp u or numberp v then nil
  59. else if u=v then u
  60. else if atom u and u memq frlis!* then t
  61. %to allow the most general pattern matching to occur;
  62. else if (lambda x; x and lndepends(cdr x,v)) assoc(u,depl!*)
  63. then t
  64. else if not atom u and idp car u and get(car u,'dname) then
  65. (if depends!-fn then apply2(depends!-fn,u,v) else nil)
  66. where (depends!-fn = get(car u,'domain!-depends!-fn))
  67. else if not atomf u
  68. and (lndepends(cdr u,v) or ndepends(car u,v)) then t
  69. else if atomf v or idp car v and get(car v,'dname) then nil
  70. % else ndependsl(u,cdr v);
  71. else nil;
  72. %%% Make depends from ALG into ndepends from EXCALC (identical except
  73. %%% for atomf test which treats indexed variables as atoms).
  74. copyd('depends,'ndepends);
  75. symbolic procedure lndepends(u,v);
  76. % Need to allow the possibility that U is an atom because the int
  77. % package calls depends with sq instead of prefix.
  78. if null u then nil
  79. else if atom u then ndepends(u,v)
  80. else ndepends(car u,v) or lndepends(cdr u,v);
  81. % changed first u -> v (error otherwise)
  82. symbolic procedure ndependsl(u,v);
  83. v and (ndepends(u,car v) or ndependsl(u,cdr v));
  84. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  85. % OLD PATCHES: REMOVE ONCE IN PATCHES.RED!!! %
  86. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  87. fluid '(!*edsverbose !*edsdebug !*arbvars !*varopt !*groebopt
  88. !*solveinconsistent depl!*);
  89. %%% SOLVE changes
  90. % Changed depl!* line to work for non-atom kernels as well.
  91. fluid '(!*expandexpt); % from simp.red
  92. fluid '( system!* % system to be solved
  93. osystem!* % original system on input
  94. uv!* % user supplied variables
  95. iv!* % internal variables
  96. fv!* % restricted variables
  97. kl!* % kernels to be investigated
  98. sub!* % global substitutions
  99. inv!* % global inverse substitutions
  100. depl!* % REDUCE dependency list
  101. !*solvealgp % true if using this module
  102. solvealgdb!* % collecting some data
  103. last!-vars!* % collection of innermost aux variables
  104. const!-vars!* % variables representing constants
  105. root!-vars!* % variables representing root expressions
  106. !*expli % local switch: explicit solution
  107. groebroots!* % predefined roots from input surds
  108. !*test_solvealg % debugging support
  109. !*arbvars
  110. );
  111. fluid '(!*trnonlnr);
  112. % If set on, the modified system and the Groebner result
  113. % or the reason for the failure are printed.
  114. global '(loaded!-packages!* !!arbint);
  115. symbolic procedure solvenonlnrsys2();
  116. % Main driver. We need non-local exits here
  117. % because of possibly hidden non algebraic variable
  118. % dependencies.
  119. if null !*solvealgp then system!*:='(FAILED) else % against recursion.
  120. (begin scalar iv!*,kl!*,inv!*,fv!*,r,w,!*solvealgp,solvealgdb!*,sub!*;
  121. scalar last!-vars!*,groebroots!*,const!-vars!*,root!-vars!*;
  122. % preserving the variable sequence if *varopt is off
  123. % if not !*varopt then depl!* :=
  124. % append(pair(uv!*,append(cdr uv!*,{gensym()})),depl!*);
  125. if not !*varopt then depl!* :=
  126. append(foreach l on uv!* collect l,depl!*);
  127. % hiding dmode because exponentials need integers.
  128. for each f in system!* do solvealgk0
  129. (if dmode!* then numr subf(f,nil) where dmode!*=nil else f);
  130. if !*trnonlnr then print list("original system:",system!*);
  131. if !*trnonlnr then print list("original kernels:",kl!*);
  132. if null cdr system!* then
  133. if (smemq('sin,system!*)or smemq('cos,system!*)) and
  134. (r:=solvenonlnrtansub(prepf(w:=car system!*),car uv!*))
  135. and car r
  136. then return solvenonlnrtansolve(r,car uv!*,w)
  137. else if (smemq('sinh,system!*)or smemq('cosh,system!*)) and
  138. (r:=solvenonlnrtanhsub(prepf(w:=car system!*),car uv!*))
  139. and car r
  140. then return solvenonlnrtanhsolve(r,car uv!*,w);
  141. if atom (errorset('(solvealgk1),!*trnonlnr,nil))
  142. where dmode!*=nil
  143. then return (system!*:='(FAILED));
  144. system!*:='LIST.for each p in system!* collect prepf p;
  145. if not('groebner memq loaded!-packages!*)
  146. then load!-package 'groebner;
  147. for each x in iv!* do if not member(x,last!-vars!*) then
  148. for each y in last!-vars!* do depend1(x,y,t);
  149. iv!* := sort(iv!*,function (lambda(a,b);depends(a,b)));
  150. if !*trnonlnr then
  151. << prin2t "Entering Groebner for system";
  152. writepri(mkquote system!*,'only);
  153. writepri(mkquote('LIST.iv!*), 'only);
  154. >>;
  155. r := list(system!*,'LIST.iv!*);
  156. r := groesolveeval r;
  157. if !*trnonlnr then
  158. << prin2t "leaving Groebner with intermediate result";
  159. writepri(mkquote r,'only);
  160. terpri(); terpri();
  161. >>;
  162. if 'sin memq solvealgdb!* then r:=solvealgtrig2 r;
  163. if 'sinh memq solvealgdb!* then r:=solvealghyp2 r;
  164. r:= if r='(LIST) then '(INCONSISTENT) else solvealginv r;
  165. system!* := r; % set value aside
  166. return r;
  167. end) where depl!*=depl!* ;
  168. % Make variable dependency override reordering.
  169. fluid '(!*trsparse);
  170. symbolic procedure solvesparsecheck(sys,vl);
  171. % sys: list of sf, vl: list of kernel
  172. % -> solvesparsecheck: nil or {list of sf,list of kernel}
  173. % This program checks for a sparse linear system. If the
  174. % system is sparse enough, it returns (exlis.varlis) reordered
  175. % such that a maximum triangular upper diagonal form is
  176. % established. Otherwise the result is NIL.
  177. begin scalar vl1,xl,sys1,q,x,y;
  178. integer sp;
  179. % First collect a list vl1 where each variable is followed
  180. % by the number of equations where it occurs, and then
  181. % by the number of other variables which occur in these
  182. % equations (connectivity). At the same time, collect a measure
  183. % of the sparsity.
  184. sp:=0;
  185. vl1:= for each x in vl collect x . 0 . nil;
  186. foreach q in sys do
  187. foreach x in (xl := intersection(topkerns q,vl)) do
  188. <<y := assoc(x,vl1);
  189. cdr y := (cadr y + 1) . union(xl,cddr y);
  190. sp := sp + 1>>;
  191. foreach p in vl1 do
  192. cddr p := length cddr p - 1; % could drop the -1
  193. % Drop out if density > 80%
  194. if sp > length sys * length vl * 0.8 then
  195. <<if !*trsparse then prin2t "System is not very sparse";
  196. return nil>>;
  197. % If varopt is on, sort variables first by least occurrences and then
  198. % least connectivity, but allow dependency to override.
  199. % Reset kernel order and reorder equations.
  200. if !*trsparse then
  201. solvesparseprint("Original sparse system",sys,vl);
  202. if !*varopt then
  203. << vl1 := sort(vl1,function solvevarordp);
  204. vl1 := foreach x in vl1 collect car x;
  205. % if !*trsparse then lpriw("Optimal variable order:",vl1);
  206. % foreach k in reverse vl1 do updkorder k;
  207. % vl1 := sort(vl1,function solvevarordp1);
  208. vl1 := solvevaradjust vl1;
  209. % if !*trsparse then lpriw("Adjusted variable order:",vl1);
  210. foreach k in reverse vl1 do updkorder k;
  211. sys := for each q in sys collect reorder q >>
  212. else vl1 := foreach x in vl1 collect car x;
  213. % Next sort equations in ascending order of their first variable
  214. % and then descending order of the next variable.
  215. sys1:= (nil . nil) . foreach x in vl1 collect x . nil;
  216. foreach q in sys do
  217. <<if domainp q or not member(mvar q,vl1) then y := assoc(nil,sys1)
  218. else y := assoc(mvar q,sys1);
  219. cdr y := q . cdr y>>;
  220. foreach p in cdr sys1 do
  221. if cdr p then cdr p := sort(cdr p, function solvesparsesort);
  222. % Finally split off a leading diagonal system and push the remaining
  223. % equations down.
  224. sys := nconc(foreach p in sys1 join if cdr p then {cadr p},
  225. reversip foreach p in sys1 join if cdr p then cddr p);
  226. if !*trsparse then
  227. solvesparseprint("Variables and/or equations rearranged",sys,vl1);
  228. return sys.vl1;
  229. end;
  230. symbolic procedure solvevarordp(x,y);
  231. cadr x < cadr y or
  232. cadr x = cadr y and cddr x < cddr y;
  233. symbolic procedure solvevarordp1(x,y);
  234. % This is incomplete, since it is not transitive
  235. depends(x,y) or
  236. not depends(y,x) and ordop(x,y);
  237. symbolic procedure solvevaradjust u;
  238. begin scalar v,y;
  239. if null u then return nil;
  240. v := foreach x in u join
  241. << y := assoc(x,depl!*);
  242. if null y or null xnp(cdr y,u) then {x} >>;
  243. return nconc(solvevaradjust setdiff(u,v),v);
  244. end;
  245. % Usually solve goes to the Cramer method since the expressions
  246. % contain exponentials. The Bareiss code should work, so disable this.
  247. symbolic procedure exptexpflistp u;
  248. nil;
  249. endmodule;
  250. end;