123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- module changevr; % Facility to perform CHANGE of independent VARs.
- %*********************************************************************;
- % ------------------------------- ;
- % C H A N G E V A R ;
- % ------------------------------- ;
- % ;
- % A REDUCE facility to perform CHANGE of independent VARiable(s) ;
- % in differential equation (or a set of them). ;
- % ;
- % ;
- % Author : Gokturk Ucoluk ;
- % Date : Oct. 1989 ;
- % Place : Middle East Tech. Univ., Physics Dept., Turkey. ;
- % Email : A07917 @ TRMETU.BITNET or A06794 @ TRMETU.BITNET ;
- % ;
- % Version: 1.00 ;
- % ;
- % ( *** Requires: REDUCE 3.0 or greater *** ) ;
- % ( *** Requires: Matrix package to be present *** ) ;
- % ;
- % There exists a document written in LaTeX that explains the ;
- % package in more detail. ;
- % ;
- % Keywords : differential equation, change of variable, Jacobian ;
- % ;
- %*********************************************************************;
- create!-package('(changevr),'(contrib misc));
- load!-package 'matrix;
- fluid '(powlis!* wtl!*);
- global '(!*derexp !*dispjacobian);
- switch derexp, dispjacobian ; % on derexp : Smart chain ruling
- % on dispjacobian : Displays inverse
- % Jacobian.
- symbolic procedure simpchangevar v;
- begin scalar u,f,j,dvar,flg;
- dvar := if pairp car v then cdar v else car v.nil;
- v := cdr v; % Dvar: list of depend. var
- u := if pairp car v then cdar v else car v.nil;
- v := cdr v; % u: list of new variables
- if eqcar(car v,'list) then v := append(cdar v,cdr v);
- while cdr v do
- << if caar v neq 'equal
- then rederr "improper new variable declaration";
- f := cdar v . f; % f: list of entries (oldvar func(newvrbs))
- v := cdr v >>; % i i
- v := reval car v; % v: holds now last expression (maybe a list)
- if length u < length f then rederr "Too few new variables"
- else if length u > length f then rederr "Too few old variables";
- % Now we form the Jacobian matrix ;
- j := for each entry in f collect
- for each newvrb in u collect
- reval list('df,cadr entry, newvrb);
- j := cdr aeval list('quotient,1,'mat.j);
- % j: holds inverse Jacobian.
- % We have to define the dependencies of old variables to new
- % variables.
- for each new in u do
- for each old in f do
- depend1(new, car old, t);
- % Below everything is perplexed :
- % The aim is to introduce LET DF(new ,old ) = jacobian
- % row col row,col
- % With the pairing trick below we do it in one step.
- % new : car row, old : caar col, jacobian : cdr col
- % row col row,col
- %
- for each row in pair(u,j) do
- for each col in pair(f,cdr row) do
- <<
- let2(list('df,car row,caar col), sqchk cdr col, nil, t);
- if !*dispjacobian and !*msg then
- mathprint list('equal,list('df,car row,caar col),
- sqchk cdr col)
- >>;
- flg := !*derexp;
- !*derexp := t;
- v := changearg(dvar,u,v);
- for each entry in f do
- v := subcare(car entry, cadr entry, v);
- % now here comes the striking point ... we evaluate the last
- % argument.
- v := simp!* v;
- % Now clean up the mess of LET;
- for each new in u do
- for each old in f do
- << let2(list('df,new,car old), nil, nil, nil);
- let2(list('df,new,car old), nil, t, nil) >>;
- !*derexp := flg;
- return v;
- end;
- put('changevar,'simpfn,'simpchangevar);
- symbolic procedure changearg(f,u,x);
- if atom x then x
- else if car x memq f then car x . u
- else changearg(f,u,car x) . changearg(f,u,cdr x);
- symbolic procedure subcare(x,y,z); % shall be used after changearg ;
- if null z then nil
- else if x = z then y
- else if atom z or get(car z,'subfunc) then z
- else (subcare(x,y,car z) . subcare(x,y,cdr z));
- % Updated version of DIFFP.. chain rule handling is smarter. ;
- % Example: If F is an operator and R has a implicit dependency on X,
- % declared by a preceding DEPEND R,X .. then the former version
- % of DIFFP, provided in REDUCE 3.3, was such that an algebraic
- % evaluation of DF(F(R),X) will evaluate to itself, that
- % means no change will happen. With the below given update this
- % is improved. If the new provided flag DEREXP is OFF then
- % the differentiation functions exactly like it was before,
- % but if DEREXP is ON then the chain rule is taken further to
- % yield the result: DF(F(R),R)*DF(R,X) .
- remflag('(diffp),'lose); % Since we want to reload it.
- symbolic procedure diffp(u,v);
- %U is a standard power, V a kernel.
- % Value is the standard quotient derivative of U wrt V.
- begin scalar n,w,x,y,z,key; integer m;
- n := cdr u; %integer power;
- u := car u; %main variable;
- if u eq v and (w := 1 ./ 1) then go to e
- else if atom u then go to f
- %else if (x := assoc(u,dsubl!*)) and (x := atsoc(v,cdr x))
- % and (w := cdr x) then go to e %deriv known;
- %DSUBL!* not used for now;
- else if (not atom car u and (w:= difff(u,v)))
- or (car u eq '!*sq and (w:= diffsq(cadr u,v)))
- then go to c %extended kernel found;
- else if x := get(car u,'dfform) then return apply3(x,u,v,n)
- else if x:= get(car u,dfn_prop u) then nil
- else if car u eq 'plus and (w:=diffsq(simp u,v))
- then go to c
- else go to h; %unknown derivative;
- y := x;
- z := cdr u;
- a: w := diffsq(simp car z,v) . w;
- if caar w and null car y then go to h; %unknown deriv;
- y := cdr y;
- z := cdr z;
- if z and y then go to a
- else if z or y then go to h; %arguments do not match;
- y := reverse w;
- z := cdr u;
- w := nil ./ 1;
- b: %computation of kernel derivative;
- if caar y
- then w := addsq(multsq(car y,simp subla(pair(caar x,z),
- cdar x)),
- w);
- x := cdr x;
- y := cdr y;
- if y then go to b;
- c: %save calculated deriv in case it is used again;
- %if x := atsoc(u,dsubl!*) then go to d
- %else x := u . nil;
- %dsubl!* := x . dsubl!*;
- % d: rplacd(x,xadd(v . w,cdr x,t));
- e: %allowance for power;
- %first check to see if kernel has weight;
- if (x := atsoc(u,wtl!*))
- then w := multpq('k!* .** (-cdr x),w);
- m := n-1;
- % Evaluation is far more efficient if results are rationalized.
- return rationalizesq if n=1 then w
- else if flagp(dmode!*,'convert)
- and null(n := int!-equiv!-chk
- apply1(get(dmode!*,'i2d),n))
- then nil ./ 1
- else multsq(!*t2q((u .** m) .* n),w);
- f: % Check for possible unused substitution rule.
- if not depends(u,v)
- and (not (x:= atsoc(u,powlis!*))
- or not smember(v,simp cadddr x))
- then return nil ./ 1;
- w := list('df,u,v);
- go to j;
- h: %final check for possible kernel deriv;
- y := nil;
- if car u eq 'df then key:=t;
- w := if key then 'df . cadr u . derad(v,cddr u)
- else list('df,u,v);
- y := cddr u;
- w := if (x := opmtch w) then simp x
- else if not depends(cadr w,caddr w) then nil ./ 1
- else if !*derexp then
- begin
- if atom cadr w then return mksq(w,1);
- w := nil ./ 1;
- for each m in cdr(if key then cadr u else u) do
- w := addsq(multsq(
- if (x := opmtch (z :=
- 'df . if key then (cadr u.derad(m,y))
- else list(u,m) )) then
- simp x else mksq(z,1),
- diffsq(simp m,v)),
- w);
- return w
- end
- else mksq(w,1);
- go to e;
- j: w := if x := opmtch w then simp x else mksq(w,1);
- go to e
- end;
- endmodule;
- end;
|