Artifact 5617f36ce05648d408c91770939317a59b0bbfb0d2d29176bcd557f363faadd7:
- Executable file
r37/packages/taylor/tayutils.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 19176) [annotate] [blame] [check-ins using] [more...]
- Executable file
r38/packages/taylor/tayutils.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 19176) [annotate] [blame] [check-ins using]
module TayUtils; %***************************************************************** % % Utility functions that operate on Taylor kernels % %***************************************************************** exports add!-degrees, add!.comp!.tp!., check!-for!-cst!-Taylor, comp!.tp!.!-p, delete!-superfluous!-coeffs, enter!-sorted, exceeds!-order, exceeds!-order!-variant, find!-non!-zero, get!-cst!-coeff, inv!.tp!., is!-neg!-pl, min2!-order, mult!.comp!.tp!., rat!-kern!-pow, replace!-next, subtr!-degrees, subtr!-tp!-order, taydegree!<, taydegree!-strict!<!=, taymincoeff, tayminpowerlist, Taylor!*!-constantp, Taylor!*!-nzconstantp, Taylor!*!-onep, Taylor!*!-zerop, TayTpmin2, tp!-greaterp, truncate!-coefflist, truncate!-Taylor!*; imports % from the REDUCE kernel: ./, gcdn, geq, lastpair, mkrn, neq, nth, numr, reversip, % from the header module: !*tay2q, get!-degree, get!-degreelist, make!-cst!-powerlist, Make!-Taylor!*, nzerolist, prune!-coefflist, TayCfPl, TayCfSq, TayCoeffList, TayGetCoeff, TayFlags, Taylor!:, TayOrig, TayTemplate, TayTpElNext, TayTpElOrder, TayTpElPoint, TayTpElVars, TpDegreeList, TpNextList, % from module Tayintro: confusion, % from module TayUtils: TayCoeffList!-zerop; symbolic procedure add!-degrees (dl1, dl2); % % calculates the element-wise sum of two degree lists dl1, dl2. % Taylor!: begin scalar dl,u,v,w; while dl1 do << u := car dl1; v := car dl2; w := nil; while u do << w := (car u + car v) . w; u := cdr u; v := cdr v>>; dl := reversip w . dl; dl1 := cdr dl1; dl2 := cdr dl2>>; return reversip dl end; symbolic procedure subtr!-degrees(dl1,dl2); % % calculates the element-wise difference of two degree lists dl1, dl2. % Taylor!: begin scalar dl,u,v,w; while dl1 do << u := car dl1; v := car dl2; w := nil; while u do << w := (car u - car v) . w; u := cdr u; v := cdr v>>; dl := reversip w . dl; dl1 := cdr dl1; dl2 := cdr dl2>>; return reversip dl end; symbolic procedure find!-non!-zero pl; % % pl is a power list. Returns pair (n . m) of position of first % non zero degree. % begin scalar u; integer n, m; n := 1; loop: m := 1; u := car pl; loop2: if not (car u = 0) then return (n . m); u := cdr u; m := m + 1; if not null u then goto loop2; pl := cdr pl; n := n + 1; if null pl then confusion 'find!-non!-zero; goto loop end$ symbolic procedure lcmn(n,m); % % returns the least common multiple of two integers m,n. % n*(m/gcdn(n,m)); symbolic smacro procedure get!-denom expo; if atom expo then 1 else cddr expo; symbolic procedure get!-denom!-l expol; <<for each el in cdr expol do result := lcmn(result,get!-denom el); result>> where result := get!-denom car expol; symbolic procedure get!-denom!-ll(dl,pl); if null dl then nil else lcmn(car dl,get!-denom!-l car pl) . get!-denom!-ll(cdr dl, cdr pl); symbolic procedure smallest!-increment cfl; if null cfl then confusion 'smallest!-increment else begin scalar result; result := for each l in TayCfPl car cfl collect get!-denom!-l l; for each el in cdr cfl do result := get!-denom!-ll(result,TayCfPl el); return for each n in result collect if n=1 then n else mkrn(1,n); end; symbolic procedure common!-increment(dl1,dl2); begin scalar result,l; loop: l := lcmn(get!-denom car dl1,get!-denom car dl2); result := (if l=1 then l else mkrn(1,l)) . result; dl1 := cdr dl1; dl2 := cdr dl2; if not null dl1 then goto loop else if not null dl2 then confusion 'common!-increment else return reversip result end; symbolic procedure min2!-order(nextlis,ordlis,dl); % % (List of Integers, List of Integers, TayPowerList) -> Boolean % % nextlis is the list of TayTpElNext numbers, % ordlis the list if TayTpElOrder numbers, % dl the degreelist of a coefficient. % Dcecrease the TayTpElNext number if the degree is greater than % the order, but smaller than the next. % Returns the corrected nextlis. % if null nextlis then nil else (Taylor!: (if dg > car ordlis then min2(dg,car nextlis) else car nextlis) where dg := get!-degree car dl) . min2!-order(cdr nextlis,cdr ordlis,cdr dl); symbolic procedure replace!-next(tp,nl); % % Given a template and a list of exponents, returns a template % with the next part replaced. % if null tp then nil else {TayTpElVars car tp, TayTpElPoint car tp, TayTpElOrder car tp, car nl} . replace!-next(cdr tp,cdr nl); symbolic procedure comp!.tp!.!-p (u, v); % % Checks templates of Taylor kernels u and v for compatibility, % i.e. whether variables and expansion points match. % Returns t if possible. % begin; u := TayTemplate u; v := TayTemplate v; if length u neq length v then return nil; loop: if not (TayTpElVars car u = TayTpElVars car v and TayTpElPoint car u = TayTpElPoint car v) then return nil; u := cdr u; v := cdr v; if null u then return t; goto loop end$ symbolic procedure add!.comp!.tp!.(u,v); % % Checks templates of Taylor kernels u and v for compatibility % when adding them, i.e. whether variables and expansion points % match. % Returns either a list containing a new Taylor template whose % degrees are the minimum of the corresponding degrees of u and v, % or nil if variables or expansion point(s) do not match. % Taylor!: begin scalar w; u := TayTemplate u; v := TayTemplate v; if length u neq length v then return nil; if null u then return {nil}; loop: if not (TayTpElVars car u = TayTpElVars car v and TayTpElPoint car u = TayTpElPoint car v) then return nil else w := {TayTpElVars car u, TayTpElPoint car u, min2(TayTpElOrder car u,TayTpElOrder car v), min2(TayTpElNext car u,TayTpElNext car v)} . w; u := cdr u; v := cdr v; if null u then return {reversip w}; goto loop end; symbolic procedure taymindegreel(pl,dl); Taylor!: if null pl then nil else min2(get!-degree car pl,car dl) . taymindegreel(cdr pl,cdr dl); symbolic procedure get!-min!-degreelist cfl; Taylor!: if null cfl then confusion 'get!-min!-degreelist else if null cdr cfl then get!-degreelist TayCfPl car cfl else taymindegreel(TayCfPl car cfl, get!-min!-degreelist cdr cfl); symbolic procedure mult!.comp!.tp!.(u,v,div!?); % % Checks templates of Taylor kernels u and v for compatibility % when multiplying or dividing them, i.e., whether variables and % expansion points match. The difference to addition is that % in addition to the new template it returns two degreelists % and two nextlists to be used by truncate!-coefflist which % are made up so that the kernels have the same number of terms. % Taylor!: begin scalar cf1,cf2,next1,next2,ord1,ord2,w, !#terms!-1,!#terms!-next,dl1,dl2,mindg; cf1 := prune!-coefflist TayCoeffList u; if null cf1 then dl1 := nzerolist length TayTemplate u else dl1 := get!-min!-degreelist cf1; cf2 := prune!-coefflist TayCoeffList v; if null cf2 then dl2 := nzerolist length TayTemplate v else dl2 := get!-min!-degreelist cf2; u := TayTemplate u; v := TayTemplate v; if length u neq length v then return nil; if null u then return {nil,nil,nil,nil,nil}; loop: if not (TayTpElVars car u = TayTpElVars car v and TayTpElPoint car u = TayTpElPoint car v) then return nil; mindg := if div!? then car dl1 - car dl2 else car dl1 + car dl2; !#terms!-1 := min2(TayTpElOrder car u - car dl1, TayTpElOrder car v - car dl2); !#terms!-next := min2(TayTpElNext car u - car dl1, TayTpElNext car v - car dl2); ord1 := (!#terms!-1 + car dl1) . ord1; ord2 := (!#terms!-1 + car dl2) . ord2; next1 := (!#terms!-next + car dl1) . next1; next2 := (!#terms!-next + car dl2) . next2; w := {TayTpElVars car u,TayTpElPoint car u, mindg + !#terms!-1,mindg + !#terms!-next} . w; u := cdr u; v := cdr v; dl1 := cdr dl1; dl2 := cdr dl2; if null u then return {reversip w, reversip ord1, reversip ord2, reversip next1, reversip next2}; goto loop end; symbolic procedure inv!.tp!. u; % % Checks template of Taylor kernel u for inversion. It returns a % template (to be used by truncate!-coefflist) % which is made up so that the resulting kernel has the correct % number of terms. % Taylor!: begin scalar w,cf,!#terms!-1,!#terms!-next,dl,mindg; cf := prune!-coefflist TayCoeffList u; if null cf then dl := nzerolist length TayTemplate u else dl := get!-degreelist TayCfPl car cf; u := TayTemplate u; if null u then return {nil,nil}; loop: mindg := - car dl; !#terms!-1 := TayTpElOrder car u - car dl; !#terms!-next := TayTpElNext car u - car dl; w := {TayTpElVars car u,TayTpElPoint car u,mindg + !#terms!-1, mindg + !#terms!-next} . w; u := cdr u; dl := cdr dl; if null u then return {reversip w}; goto loop end; symbolic smacro procedure taycoeff!-before(cc1,cc2); % % (TayCoeff, TayCoeff) -> Boolean % % returns t if coeff cc1 is ordered before cc2 % both are of the form (degreelist . sq) % taydegree!<(TayCfPl cc1,TayCfPl cc2); symbolic procedure taydegree!<(u,v); % % (TayPowerList, TayPowerList) -> Boolean % % returns t if coefflist u is ordered before v % Taylor!: begin scalar u1,v1; loop: u1 := car u; v1 := car v; loop2: if car u1 > car v1 then return nil else if car u1 < car v1 then return t; u1 := cdr u1; v1 := cdr v1; if not null u1 then go to loop2; u := cdr u; v := cdr v; if not null u then go to loop end; symbolic procedure taydegree!-strict!<!=(u,v); % % (TayPowerList, TayPowerList) -> Boolean % % returns t if every component coefflist u is less or equal than % respective component of v % Taylor!: begin scalar u1,v1; loop: u1 := car u; v1 := car v; loop2: if car u1 > car v1 then return nil; u1 := cdr u1; v1 := cdr v1; if not null u1 then go to loop2; u := cdr u; v := cdr v; if not null u then go to loop; return t end; symbolic procedure exceeds!-order(ordlis,cf); % % (List of Integers, TayPowerlist) -> Boolean % % Returns t if the degrees in coefficient cf are greater or % equal than those in the degreelist ordlis % if null ordlis then nil else Taylor!:(get!-degree car cf >= car ordlis) or exceeds!-order(cdr ordlis,cdr cf); symbolic procedure exceeds!-order!-variant(ordlis,cf); % % (List of Integers, TayPowerlist) -> Boolean % % Returns t if the degrees in coefficient cf are greater or % equal than those in the degreelist ordlis % if null ordlis then nil else Taylor!:(get!-degree car cf > car ordlis) or exceeds!-order!-variant(cdr ordlis,cdr cf); symbolic procedure enter!-sorted (u, alist); % % (TayCoeff, TayCoeffList) -> TayCoeffList % % enters u into the alist alist according to the standard % ordering for the car part % if null alist then {u} else if taycoeff!-before (u, car alist) then u . alist else car alist . enter!-sorted (u, cdr alist)$ symbolic procedure delete!-superfluous!-coeffs(cflis,pos,n); % % (TayCoeffList, Integer, Integer) -> TayCoeffList % % This procedure deletes all coefficients of a TayCoeffList cflis % whose degree in position pos exceeds n. % Taylor!: for each cc in cflis join (if get!-degree nth(TayCfPl cc,pos) > n then nil else {cc}); symbolic procedure truncate!-coefflist (cflis, dl); % % (TayCoeffList, List of Integers) -> TayCoeffList % % Deletes all coeffs from coefflist cflis that are equal or greater % in degree than the corresponding degree in the degreelist dl. % begin scalar l; for each cf in cflis do if not exceeds!-order (dl, TayCfPl cf) then l := cf . l; return reversip l end; symbolic procedure TayTp!-min2(tp1,tp2); % % finds minimum (w.r.t. Order and Next parts) of compatible % templates tp1 and tp2 % Taylor!: if null tp1 then nil else if not (TayTpElVars car tp1 = TayTpElVars car tp2 and TayTpElPoint car tp1 = TayTpElPoint car tp2) then confusion 'TayTpmin2 else {TayTpElVars car tp1,TayTpElPoint car tp2, min2(TayTpElOrder car tp1,TayTpElOrder car tp2), min2(TayTpElNext car tp1,TayTpElNext car tp2)} . TayTp!-min2(cdr tp1,cdr tp2); symbolic procedure truncate!-Taylor!*(tay,ntp); % % tcl is a coefflist for template otp % truncate it to coefflist for template ntp % Taylor!: begin scalar nl,ol,l,tp,tcl,otp; tcl := TayCoeffList tay; otp := TayTemplate tay; tp := for each pp in pair(ntp,otp) collect {TayTpElVars car pp, TayTpElPoint car pp, min2(TayTpElOrder car pp,TayTpElOrder cdr pp), min2(TayTpElNext car pp,TayTpElNext cdr pp)}; nl := TpNextList tp; ol := TpDegreeList tp; for each cf in tcl do if not null numr TayCfSq cf % then ((if not exceeds!-order(nl,pl) then l := cf . l % else nl := min2!-order(nl,ol,pl)) then ((if not exceeds!-order!-variant(ol,pl) then l := cf . l else nl := min2!-order(nl,ol,pl)) where pl := TayCfPl cf); return make!-Taylor!*(reversip l,replace!-next(tp,nl), TayOrig tay,TayFlags tay) end; symbolic procedure tp!-greaterp(tp1,tp2); % % Given two templates tp1 and tp2 with matching variables and % expansion points this function returns t if the expansion % order wrt at least one variable is greater in tp1 than in tp2. % if null tp1 then nil else Taylor!: (TayTpElOrder car tp1 > TayTpElOrder car tp2) or tp!-greaterp(cdr tp1,cdr tp2); symbolic procedure subtr!-tp!-order(tp1,tp2); % % Given two templates tp1 and tp2 with matching variables and % expansion points this function returns the difference in their % orders. % Taylor!: if null tp1 then nil else (TayTpElOrder car tp1 - TayTpElOrder car tp2) . subtr!-tp!-order(cdr tp1,cdr tp2); comment Procedures to non-destructively modify Taylor templates; symbolic procedure addto!-all!-TayTpElOrders(tp,nl); Taylor!: if null tp then nil else {TayTpElVars car tp, TayTpElPoint car tp, TayTpElOrder car tp + car nl, TayTpElNext car tp + car nl} . addto!-all!-TayTpElOrders(cdr tp,cdr nl); symbolic procedure taymincoeff cflis; % % Returns degree of first non-zero coefficient % or 0 if there isn't any. % if null cflis then 0 else if not null numr TayCfSq car cflis then get!-degree car TayCfPl car cflis else taymincoeff cdr cflis; symbolic procedure tayminpowerlist cflis; % % Returns degreelist of first non-zero coefficient of TayCoeffList % cflis or a list of zeroes if there isn't any. % if null cflis then confusion 'tayminpowerlist else tayminpowerlist1(cflis,length TayCfPl car cflis); symbolic procedure tayminpowerlist1(cflis,l); if null cflis then nzerolist l else if null numr TayCfSq car cflis then tayminpowerlist1(cdr cflis,l) else get!-degreelist TayCfPl car cflis; symbolic procedure get!-cst!-coeff tay; TayGetCoeff(make!-cst!-powerlist TayTemplate tay,TayCoeffList tay); symbolic procedure Taylor!*!-constantp tay; Taylor!*!-constantp1(make!-cst!-powerlist TayTemplate tay, TayCoeffList tay); symbolic procedure Taylor!*!-constantp1(pl,tcf); if null tcf then t else if TayCfPl car tcf = pl then TayCoeffList!-zerop cdr tcf else if not null numr TayCfSq car tcf then nil else Taylor!*!-constantp1(pl,cdr tcf); symbolic procedure check!-for!-cst!-Taylor tay; begin scalar pl,tc; pl := make!-cst!-powerlist TayTemplate tay; tc := TayCoeffList tay; return if Taylor!*!-constantp1(pl,tc) then TayGetCoeff(pl,tc) else !*tay2q tay end; symbolic procedure Taylor!*!-nzconstantp tay; Taylor!*!-nzconstantp1(make!-cst!-powerlist TayTemplate tay, TayCoeffList tay); symbolic procedure Taylor!*!-nzconstantp1(pl,tcf); if null tcf then nil else if TayCfPl car tcf = pl then if null numr TayCfSq car tcf then nil else TayCoeffList!-zerop cdr tcf else if TayCfPl car tcf neq pl and not null numr TayCfSq car tcf then nil else Taylor!*!-nzconstantp1(pl,cdr tcf); symbolic procedure Taylor!*!-onep tay; Taylor!-onep1(make!-cst!-powerlist TayTemplate tay,TayCoeffList tay); symbolic procedure Taylor!-onep1(pl,tcf); if null tcf then nil else if TayCfPl car tcf = pl then if TayCfSq car tcf = (1 ./ 1) then TayCoeffList!-zerop cdr tcf else nil else if null numr TayCfSq car tcf then Taylor!*!-nzconstantp1(pl,cdr tcf) else nil; symbolic procedure is!-neg!-pl pl; % % Returns t if any of the exponents in pl is negative. % Taylor!: if null pl then nil else if get!-degree car pl < 0 then t else is!-neg!-pl cdr pl; symbolic procedure rat!-kern!-pow(x,pos); % % check that s.f. x is a kernel to a rational power. % if pos is t allow only positive exponents. % returns pair (kernel . power) % begin scalar y; integer n; if domainp x or not null red x or not (lc x=1) then return nil; n := ldeg x; x := mvar x; Taylor!: if eqcar(x,'sqrt) then return (cadr x . mkrn(1,2)*n) else if eqcar(x,'expt) and (y := simprn{caddr x}) then if null pos or (y := car y)>0 then return (cadr x . (y*n)) else return nil else return (x . n) end; endmodule; end;