123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- 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;
|