changevr.red 9.2 KB

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