changevr.red 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. module changevr; % Facility to perform CHANGE of independent VARs.
  2. %*********************************************************************;
  3. % ------------------------------- ;
  4. % C H A N G E V A R ;
  5. % ------------------------------- ;
  6. % ;
  7. % A REDUCE facility to perform CHANGE of independent VARiable(s) ;
  8. % in differential equation (or a set of them). ;
  9. % ;
  10. % ;
  11. % Author : Gokturk Ucoluk ;
  12. % Date : Oct. 1989 ;
  13. % Place : Middle East Tech. Univ., Physics Dept., Turkey. ;
  14. % Email : A07917 @ TRMETU.BITNET or A06794 @ TRMETU.BITNET ;
  15. % ;
  16. % Version: 1.00 ;
  17. % ;
  18. % ( *** Requires: REDUCE 3.0 or greater *** ) ;
  19. % ( *** Requires: Matrix package to be present *** ) ;
  20. % ;
  21. % There exists a document written in LaTeX that explains the ;
  22. % package in more detail. ;
  23. % ;
  24. % Keywords : differential equation, change of variable, Jacobian ;
  25. % ;
  26. %*********************************************************************;
  27. create!-package('(changevr),'(contrib misc));
  28. load!-package 'matrix;
  29. fluid '(powlis!* wtl!*);
  30. global '(!*derexp !*dispjacobian);
  31. switch derexp, dispjacobian ; % on derexp : Smart chain ruling
  32. % on dispjacobian : Displays inverse
  33. % Jacobian.
  34. symbolic procedure simpchangevar v;
  35. begin scalar u,f,j,dvar,flg;
  36. dvar := if pairp car v then cdar v else car v.nil;
  37. v := cdr v; % Dvar: list of depend. var
  38. u := if pairp car v then cdar v else car v.nil;
  39. v := cdr v; % u: list of new variables
  40. if eqcar(car v,'list) then v := append(cdar v,cdr v);
  41. while cdr v do
  42. << if caar v neq 'equal
  43. then rederr "improper new variable declaration";
  44. f := cdar v . f; % f: list of entries (oldvar func(newvrbs))
  45. v := cdr v >>; % i i
  46. v := reval car v; % v: holds now last expression (maybe a list)
  47. if length u < length f then rederr "Too few new variables"
  48. else if length u > length f then rederr "Too few old variables";
  49. % Now we form the Jacobian matrix ;
  50. j := for each entry in f collect
  51. for each newvrb in u collect
  52. reval list('df,cadr entry, newvrb);
  53. j := cdr aeval list('quotient,1,'mat.j);
  54. % j: holds inverse Jacobian.
  55. % We have to define the dependencies of old variables to new
  56. % variables.
  57. for each new in u do
  58. for each old in f do
  59. depend1(new, car old, t);
  60. % Below everything is perplexed :
  61. % The aim is to introduce LET DF(new ,old ) = jacobian
  62. % row col row,col
  63. % With the pairing trick below we do it in one step.
  64. % new : car row, old : caar col, jacobian : cdr col
  65. % row col row,col
  66. %
  67. for each row in pair(u,j) do
  68. for each col in pair(f,cdr row) do
  69. <<
  70. let2(list('df,car row,caar col), sqchk cdr col, nil, t);
  71. if !*dispjacobian and !*msg then
  72. mathprint list('equal,list('df,car row,caar col),
  73. sqchk cdr col)
  74. >>;
  75. flg := !*derexp;
  76. !*derexp := t;
  77. v := changearg(dvar,u,v);
  78. for each entry in f do
  79. v := subcare(car entry, cadr entry, v);
  80. % now here comes the striking point ... we evaluate the last
  81. % argument.
  82. v := simp!* v;
  83. % Now clean up the mess of LET;
  84. for each new in u do
  85. for each old in f do
  86. << let2(list('df,new,car old), nil, nil, nil);
  87. let2(list('df,new,car old), nil, t, nil) >>;
  88. !*derexp := flg;
  89. return v;
  90. end;
  91. put('changevar,'simpfn,'simpchangevar);
  92. symbolic procedure changearg(f,u,x);
  93. if atom x then x
  94. else if car x memq f then car x . u
  95. else changearg(f,u,car x) . changearg(f,u,cdr x);
  96. symbolic procedure subcare(x,y,z); % shall be used after changearg ;
  97. if null z then nil
  98. else if x = z then y
  99. else if atom z or get(car z,'subfunc) then z
  100. else (subcare(x,y,car z) . subcare(x,y,cdr z));
  101. % Updated version of DIFFP.. chain rule handling is smarter. ;
  102. % Example: If F is an operator and R has a implicit dependency on X,
  103. % declared by a preceding DEPEND R,X .. then the former version
  104. % of DIFFP, provided in REDUCE 3.3, was such that an algebraic
  105. % evaluation of DF(F(R),X) will evaluate to itself, that
  106. % means no change will happen. With the below given update this
  107. % is improved. If the new provided flag DEREXP is OFF then
  108. % the differentiation functions exactly like it was before,
  109. % but if DEREXP is ON then the chain rule is taken further to
  110. % yield the result: DF(F(R),R)*DF(R,X) .
  111. remflag('(diffp),'lose); % Since we want to reload it.
  112. symbolic procedure diffp(u,v);
  113. %U is a standard power, V a kernel.
  114. % Value is the standard quotient derivative of U wrt V.
  115. begin scalar n,w,x,y,z,key; integer m;
  116. n := cdr u; %integer power;
  117. u := car u; %main variable;
  118. if u eq v and (w := 1 ./ 1) then go to e
  119. else if atom u then go to f
  120. %else if (x := assoc(u,dsubl!*)) and (x := atsoc(v,cdr x))
  121. % and (w := cdr x) then go to e %deriv known;
  122. %DSUBL!* not used for now;
  123. else if (not atom car u and (w:= difff(u,v)))
  124. or (car u eq '!*sq and (w:= diffsq(cadr u,v)))
  125. then go to c %extended kernel found;
  126. else if x := get(car u,'dfform) then return apply3(x,u,v,n)
  127. else if x:= get(car u,dfn_prop u) then nil
  128. else if car u eq 'plus and (w:=diffsq(simp u,v))
  129. then go to c
  130. else go to h; %unknown derivative;
  131. y := x;
  132. z := cdr u;
  133. a: w := diffsq(simp car z,v) . w;
  134. if caar w and null car y then go to h; %unknown deriv;
  135. y := cdr y;
  136. z := cdr z;
  137. if z and y then go to a
  138. else if z or y then go to h; %arguments do not match;
  139. y := reverse w;
  140. z := cdr u;
  141. w := nil ./ 1;
  142. b: %computation of kernel derivative;
  143. if caar y
  144. then w := addsq(multsq(car y,simp subla(pair(caar x,z),
  145. cdar x)),
  146. w);
  147. x := cdr x;
  148. y := cdr y;
  149. if y then go to b;
  150. c: %save calculated deriv in case it is used again;
  151. %if x := atsoc(u,dsubl!*) then go to d
  152. %else x := u . nil;
  153. %dsubl!* := x . dsubl!*;
  154. % d: rplacd(x,xadd(v . w,cdr x,t));
  155. e: %allowance for power;
  156. %first check to see if kernel has weight;
  157. if (x := atsoc(u,wtl!*))
  158. then w := multpq('k!* .** (-cdr x),w);
  159. m := n-1;
  160. % Evaluation is far more efficient if results are rationalized.
  161. return rationalizesq if n=1 then w
  162. else if flagp(dmode!*,'convert)
  163. and null(n := int!-equiv!-chk
  164. apply1(get(dmode!*,'i2d),n))
  165. then nil ./ 1
  166. else multsq(!*t2q((u .** m) .* n),w);
  167. f: % Check for possible unused substitution rule.
  168. if not depends(u,v)
  169. and (not (x:= atsoc(u,powlis!*))
  170. or not smember(v,simp cadddr x))
  171. then return nil ./ 1;
  172. w := list('df,u,v);
  173. go to j;
  174. h: %final check for possible kernel deriv;
  175. y := nil;
  176. if car u eq 'df then key:=t;
  177. w := if key then 'df . cadr u . derad(v,cddr u)
  178. else list('df,u,v);
  179. y := cddr u;
  180. w := if (x := opmtch w) then simp x
  181. else if not depends(cadr w,caddr w) then nil ./ 1
  182. else if !*derexp then
  183. begin
  184. if atom cadr w then return mksq(w,1);
  185. w := nil ./ 1;
  186. for each m in cdr(if key then cadr u else u) do
  187. w := addsq(multsq(
  188. if (x := opmtch (z :=
  189. 'df . if key then (cadr u.derad(m,y))
  190. else list(u,m) )) then
  191. simp x else mksq(z,1),
  192. diffsq(simp m,v)),
  193. w);
  194. return w
  195. end
  196. else mksq(w,1);
  197. go to e;
  198. j: w := if x := opmtch w then simp x else mksq(w,1);
  199. go to e
  200. end;
  201. endmodule;
  202. end;