1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327 |
- module TayFns;
- %*****************************************************************
- %
- % Simplification functions for special functions
- %
- %*****************************************************************
- exports taysimpexpt, taysimpatan, taysimplog, taysimpexp,
- taysimptan, taysimpsin, taysimpsinh, taysimpasin;
- imports
- % from the REDUCE kernel:
- !*f2q, !:minusp, addsq, aeval, denr, domainp, eqcar, evenp,
- freeof, invsq, kernp, lastpair, let, lprim, lnc, mk!*sq, mksq,
- multsq, mvar, negsq, neq, nlist, nth, numr, over, prepd,
- prepsq, quotsq, retimes, reval, reversip, simp, simp!*,
- simplogi, simplogsq, subs2!*, subsq, subtrsq,
- % from the header module:
- !*tay2q, !*TayExp2q, constant!-sq!-p, cst!-Taylor!*,
- find!-non!-zero, get!-degree, has!-TayVars,
- make!-cst!-powerlist, make!-Taylor!*, prune!-coefflist,
- set!-TayCoeffList, set!-TayFlags, set!-TayOrig, TayCfPl,
- TayCfSq, TayCoeffList, TayFlags, TayGetCoeff, Taylor!*p,
- Taylor!-kernel!-sq!-p, Taylor!:, TayMakeCoeff, TayOrig,
- TayTemplate, TayTpElNext, TayTpElOrder, TayTpElPoint,
- TayTpElVars, TayTpVars, TayVars, TpNextList,
- % from the module Tayintro:
- confusion, delete!-nth, delete!-nth!-nth, replace!-nth,
- replace!-nth!-nth, Taylor!-error, Taylor!-error!*,
- var!-is!-nth,
- % from the module Tayutils:
- addto!-all!-TayTpElORders, get!-cst!-coeff, is!-neg!-pl,
- smallest!-increment, subtr!-degrees, Taylor!*!-constantp,
- Taylor!*!-zerop,
- % from the module Taybasic:
- addtaylor, addtaylor!-as!-sq, invtaylor, makecoeffs0,
- makecoeffpairs, makecoeffpairs1, multtaylor,
- multtaylor!-as!-sq, multtaylorsq, negtaylor, negtaylor1,
- quottaylor,
- % from the module TayExpnd:
- taylorexpand,
- % from the module Taysimp:
- expttayrat, taysimpsq, taysimpsq!*,
- % from the module Taydiff:
- difftaylorwrttayvar,
- % from the module TayConv:
- prepTayCoeff, prepTaylor!*,
- % from the module Tayfrontend:
- taylorcombine, taylortostandard;
- fluid '(!*taylorkeeporiginal !*!*taylor!-epsilon!*!* frlis!*);
- symbolic procedure taysimpexpt u;
- %
- % Argument is of the form ('expt base exponent)
- % where both base and exponent (but a least one of them)
- % may contain Taylor kernels given as prefix forms.
- % Value is the equivalent Taylor kernel.
- %
- if not (car u eq 'expt) or cdddr u then confusion 'taysimpexpt
- else if cadr u eq 'e then taysimpexp {'exp, caddr u}
- else begin scalar bas, expn;
- bas := taysimpsq simp!* cadr u;
- expn := taysimpsq simp!* caddr u;
- if constant!-sq!-p bas then return taysimpexp
- {'exp,mk!*sq multsq(simp!*{'log,mk!*sq bas},expn)};
- if null kernp bas
- then if not(denr bas = 1)
- then return mksq({'expt,prepsq bas,prepsq expn},1)
- else if domainp numr bas
- then return taysimpexp {'exp,
- prepsq multsq(simp!* {'log,prepd numr bas},expn)}
- else return mksq({'expt,prepsq bas,prepsq expn},1);
- if fixp numr expn and fixp denr expn
- then return !*tay2q expttayrat(mvar numr bas,expn);
- if denr expn = 1 and eqcar(numr expn,'!:rn!:)
- then return !*tay2q expttayrat(mvar numr bas,cdr numr expn);
- bas := mvar numr bas;
- return
- if Taylor!*p bas
- then if Taylor!-kernel!-sq!-p expn
- then if TayTemplate bas = TayTemplate mvar numr expn
- then taysimpexp {'exp,
- mk!*sq taysimpsq
- multtaylor!-as!-sq(
- expn,
- taysimplog {'log,bas})}
- else mksq({'expt,bas,mvar numr expn},1)
- else if not has!-TayVars(bas,expn)
- then begin scalar logterm;
- logterm := taysimplog{'log,bas};
- return
- if Taylor!-kernel!-sq!-p logterm
- then taysimpexp{'exp,
- multtaylorsq(mvar numr logterm,
- expn)}
- else taysimpsq
- simp!* {'exp,mk!*sq multsq(logterm,expn)}
- end
- else mksq({'expt,bas,mk!*sq expn},1)
- else if Taylor!-kernel!-sq!-p expn
- then if not has!-TayVars(mvar numr expn,bas)
- then taysimpexp{'exp,
- multtaylorsq(mvar numr expn,
- simp!*{'log,bas})}
- else if Taylor!*!-constantp mvar numr expn
- then taylorexpand(
- simp!* {'expt,bas,
- prepTaylor!* mvar numr expn},
- TayTemplate mvar numr expn)
- else mksq({'expt,bas,mk!*sq expn},1)
- else mksq({'expt,bas,mk!*sq expn},1);
- end;
- put('expt,'taylorsimpfn,'taysimpexpt);
- symbolic procedure TayCoeffList!-union u;
- if null cdr u then car u
- else TayCoeffList!-union2 (car u, TayCoeffList!-union cdr u)$
- symbolic procedure TayCoeffList!-union2 (x, y);
- %
- % returns union of TayCoeffLists x and y
- %
- << for each w in y do
- if null (assoc (car w, x)) then x := w . x;
- x >>$
- symbolic procedure inttaylorwrttayvar(tay,var);
- %
- % integrates Taylor kernel tay wrt variable var
- %
- inttaylorwrttayvar1(TayCoeffList tay,TayTemplate tay,var)$
- symbolic procedure inttaylorwrttayvar1(tcl,tp,var);
- %
- % integrates Taylor kernel with TayCoeffList tcl and template tp
- % wrt variable var
- %
- Taylor!:
- begin scalar tt,u,w,singlist,csing; integer n,n1,m;
- u := var!-is!-nth(tp,var);
- n := car u;
- n1 := cdr u;
- tt := nth(tp,n);
- u := for each cc in tcl join <<
- m := nth(nth(TayCfPl cc,n),n1);
- if TayTpElPoint nth(tp,n) eq 'infinity
- then <<
- if m=1 then <<singlist :=
- TayMakeCoeff(
- delete!-nth!-nth(TayCfPl cc,n,n1),
- TayCfSq cc) . singlist;nil>>
- else {TayMakeCoeff(
- replace!-nth!-nth(TayCfPl cc,n,n1,m-1),
- multsq(TayCfSq cc,invsq !*TayExp2q(-m + 1)))}>>
- else <<
- if m=-1 then <<singlist :=
- TayMakeCoeff(
- delete!-nth!-nth(TayCfPl cc,n,n1),
- TayCfSq cc) . singlist;nil>>
- else {TayMakeCoeff(
- replace!-nth!-nth(TayCfPl cc,n,n1,m+1),
- multsq(TayCfSq cc,invsq !*TayExp2q(m + 1)))}>>>>;
- w := {TayTpElVars tt,TayTpElPoint tt,
- if var member TayTpElVars tt
- then if TayTpElPoint tt eq 'infinity
- then TayTpElOrder tt - 1
- else TayTpElOrder tt + 1
- else TayTpElOrder tt,
- if var member TayTpElVars tt
- then if TayTpElPoint tt eq 'infinity
- then TayTpElNext tt - 1
- else TayTpElNext tt + 1
- else TayTpElOrder tt};
- if singlist then begin scalar tpel;
- tpel := nth(tp,n);
- singlist := reversip singlist;
- if TayCfPl car singlist = '(nil) % no Taylor left
- then csing := TayCfSq car singlist
- else csing := !*tay2q
- make!-Taylor!*(
- singlist,
- replace!-nth(
- tp,n,
- {delete!-nth(TayTpElVars tpel,n1),
- TayTpElPoint tpel,
- TayTpElOrder tpel,
- TayTpElNext tpel}),
- nil,nil);
- csing := multsq(csing,simp!* {'log,nth(TayTpElVars tpel,n1)})
- end;
- return (csing . make!-Taylor!*(u,replace!-nth(tp,n,w),nil,nil))
- %
- % The following is not needed yet
- %
- % return make!-Taylor!*(
- % u,
- % replace!-nth(TayTemplate tay,n,w),
- % if !*taylorkeeporiginal and TayOrig tay
- % then simp {'int,mk!*sq TayOrig tay,var}
- % else nil,
- % TayFlags u)
- end;
- comment The inverse trigonometric and inverse hyperbolic functions
- of a Taylor kernel are calculated by first computing the
- derivative(s) with respect to the Taylor variable(s) and
- integrating the result. The derivatives can easily be
- calculated by the manipulation functions defined above.
- The method is best illustrated with an example. Let T(x)
- be a Taylor kernel depending on one variable x. To compute
- the inverse tangent T1(x) = atan(T(x)) we calculate the
- derivative
- T'(x)
- T1'(x) = ----------- .
- 2
- 1 + T(x)
- (If T and T1 depend on more than one variable replace
- the derivatives by gradients.)
- This is integrated again with the integration constant
- T1(x0) = atan(T(x0)) yielding the desired result.
- If there is more than variable we have to find the
- potential function T1(x1,...,xn) corresponding to
- the vector grad T1(x1,...,xn) which is always possible
- by construction.
- The prescriptions for the eight functions asin, acos, asec,
- acsc, asinh, acosh, asech, and acsch can be put together
- in one procedure since the expressions for their derivatives
- differ only in certain signs. The same remark applies to
- the four functions atan, acot, atanh, and acoth.
- These expressions are:
- d 1
- -- asin x = ------------- ,
- dx sqrt(1-x^2)
- d -1
- -- acos x = ------------- ,
- dx sqrt(1-x^2)
- d 1
- -- asinh x = ------------- ,
- dx sqrt(1+x^2)
- d 1
- -- acosh x = ------------- ,
- dx sqrt(x^2-1)
- d 1
- -- atan x = --------- ,
- dx 1 + x^2
- d -1
- -- acot x = --------- ,
- dx 1 + x^2
- d 1
- -- atanh x = --------- ,
- dx 1 - x^2
- d 1
- -- acoth x = --------- ,
- dx 1 - x^2
- together with the relations
- 1
- asec x = acos - ,
- x
- 1
- acsc x = asin - ,
- x
- 1
- asech x = acosh - ,
- x
- 1
- acsch x = asinh -
- x .
- This method has one drawback: it is applicable only when T(x0)
- is a regular point of the function in question. E.g., if T(x0)
- = 0, then asech(T(x)) cannot be calculated by this method, as
- asech has a logarithmic singularity at 0. This means that the
- constant term of the series cannot be determined by computing
- asech(T(x0)). In that case, we use the following relations
- instead:
- asin z = -i log(i z + sqrt(1 - z^2)),
- acos z = -i log(z + sqrt(z^2 - 1)),
- 1 1 + i z
- atan z = ----- log ---------,
- 2 i 1 - i z
- -1 i z + 1
- acot z = ----- log ---------,
- 2 i i z - 1
- asinh z = log(z + sqrt(1 + z^2)),
- acosh z = log(z + sqrt(z^2 - 1)),
- 1 1 + z
- atanh z = --- log -------,
- 2 1 - z
- 1 z + 1
- acoth z = --- log -------.
- 2 z - 1
- These formulas are applied at the following points:
- infinity for all functions,
- +i/-i for atan and acot,
- +1/-1 for atanh and acoth.
- There are still some branch points, where the calculation is
- not always possible:
- +1/-1 for asin and acos, and consequently for asec and acsc,
- +i/-i for asinh, acosh, asech and acsch.
- In these cases, the above formulas are applied as well, but
- simplification of the square roots and the logarithm may lead
- to a rather complicated result;
- symbolic procedure taysimpasin u;
- if not (car u memq '(asin acos acsc asec asinh acosh acsch asech))
- or cddr u
- then confusion 'taysimpasin
- else Taylor!:
- begin scalar l,l0,c0,v,tay0,tay,tay2,tp,singlist;
- tay0 := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p tay0
- then return mksq({car u,mk!*sq tay0},1);
- tay0 := mvar numr tay0; % asin's argument
- l0 := make!-cst!-powerlist TayTemplate tay0;
- c0 := TayGetCoeff(l0,TayCoeffList tay0);
- if car u memq '(asec acsc asech acsch)
- then if null numr c0 then return taysimpasec!*(car u,tay0)
- else tay := invtaylor tay0
- else tay := tay0;
- tp := TayTemplate tay;
- l := prune!-coefflist TayCoeffList tay;
- if null l then return !*tay2q cst!-Taylor!*(simp!* {car u,0},tp);
- if is!-neg!-pl TayCfPl car l then return taysimpasin!*(car u,tay);
- tay2 := multtaylor(tay,tay);
- if car u memq '(asin acos acsc asec)
- then tay2 := negtaylor tay2;
- tay2 := addtaylor(
- cst!-Taylor!*(
- !*f2q(if car u memq '(acosh asech) then -1 else 1),
- tp),
- tay2);
- if Taylor!*!-zerop tay2
- then Taylor!-error!*('branch!-point,car u)
- else if null numr TayGetCoeff(l0,TayCoeffList tay2)
- then return taysimpasin!*(car u,tay);
- tay2 := invtaylor expttayrat(tay2,1 ./ 2);
- if car u memq '(acos asec) then tay2 := negtaylor tay2;
- l := for each krnl in TayVars tay collect
- inttaylorwrttayvar(
- multtaylor(difftaylorwrttayvar(tay,krnl),tay2),
- krnl);
- v := TayCoeffList!-union
- for each pp in l collect TayCoeffList cdr pp;
- singlist := nil ./ 1;
- for each pp in l do
- if car pp then singlist := addsq(singlist,car pp);
- %
- % special treatment for zeroth coefficient
- %
- c0 := simp {car u,mk!*sq c0};
- v := TayMakeCoeff(l0,c0) . v;
- tay := make!-Taylor!*(
- v,
- tp,
- if !*taylorkeeporiginal and TayOrig tay
- then simp {car u,mk!*sq TayOrig tay}
- else nil,
- TayFlags tay);
- if null numr singlist then return !*tay2q tay;
- if !*taylorkeeporiginal and TayOrig tay
- then set!-TayOrig(tay,subtrsq(TayOrig tay,singlist));
- return addsq(singlist,!*tay2q tay)
- end;
- symbolic procedure taysimpasec!*(fn,tay);
- begin scalar result,tay1,tay2,i1;
- i1 := simp 'i;
- if fn memq '(asin acsc) then tay := multtaylorsq(tay,i1);
- tay1 := cst!-Taylor!*(1 ./ 1,TayTemplate tay);
- tay2 := multtaylor(tay,tay);
- if fn memq '(asec asech) then tay2 := negtaylor tay2;
- result := taysimplog {'log,
- addtaylor(
- expttayrat(addtaylor(tay2,tay1),1 ./ 2),
- tay1)};
- tay1 := taysimplog {'log,tay};
- if fn memq '(asin acos asec acsc)
- then <<result := taysimpsq negsq multsq(result,i1);
- result := addtaylor!-as!-sq(result,multsq(i1,tay1))>>
- else result := addtaylor!-as!-sq(result,
- negsq taysimplog {'log,tay});
- return taysimpsq!* result
- end;
- symbolic procedure taysimpasin!*(fn,tay);
- begin scalar result,tay1;
- if fn memq '(asin acsc)
- then tay := multtaylorsq(tay,simp 'i);
- tay1 := cst!-Taylor!*(
- (if fn memq '(asin asinh acsc acsch)
- then 1
- else -1) ./ 1,
- TayTemplate tay);
- result := taysimplog {'log,
- addtaylor(
- expttayrat(addtaylor(multtaylor(tay,tay),
- tay1),
- 1 ./ 2),
- tay)};
- if fn memq '(asin acos asec acsc)
- then result := quotsq(result,simp 'i);
- return taysimpsq!* result
- end;
- put('asin,'taylorsimpfn,'taysimpasin);
- put('acos,'taylorsimpfn,'taysimpasin);
- put('asec,'taylorsimpfn,'taysimpasin);
- put('acsc,'taylorsimpfn,'taysimpasin);
- put('asinh,'taylorsimpfn,'taysimpasin);
- put('acosh,'taylorsimpfn,'taysimpasin);
- put('asech,'taylorsimpfn,'taysimpasin);
- put('acsch,'taylorsimpfn,'taysimpasin);
- symbolic procedure taysimpatan u;
- if not (car u memq '(atan acot atanh acoth)) or cddr u
- then confusion 'taysimpatan
- else begin scalar l,l0,c0,v,tay,tay2,tp,singlist;
- tay := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p tay
- then return mksq({car u,mk!*sq tay},1);
- tay := mvar numr tay; % atan's argument
- tp := TayTemplate tay;
- l0 := make!-cst!-powerlist tp;
- l := prune!-coefflist TayCoeffList tay;
- if null l then return !*tay2q cst!-Taylor!*(simp!* {car u,0},tp);
- if is!-neg!-pl TayCfPl car l then return taysimpatan!*(car u,tay);
- c0 := get!-cst!-coeff tay;
- if car u memq '(atan acot)
- then c0 := subs2!* multsq(c0,simp 'i);
- if c0 = (1 ./ 1) or c0 = (-1 ./ 1)
- then return taysimpatan!*(car u,tay);
- tay2 := multtaylor(tay,tay);
- if car u memq '(atanh acoth) then tay2 := negtaylor tay2;
- tay2 := invtaylor addtaylor(cst!-Taylor!*(1 ./ 1,tp),tay2);
- if car u eq 'acot then tay2 := negtaylor tay2;
- l := for each krnl in TayVars tay collect
- inttaylorwrttayvar(
- multtaylor(difftaylorwrttayvar(tay,krnl),tay2),
- krnl);
- v := TayCoeffList!-union
- for each pp in l collect TayCoeffList cdr pp;
- singlist := nil ./ 1;
- for each pp in l do
- if car pp then singlist := addsq(singlist,car pp);
- %
- % special treatment for zeroth coefficient
- %
- c0 := simp {car u,
- mk!*sq TayGetCoeff(l0,TayCoeffList tay)};
- v := TayMakeCoeff (l0,c0) . v;
- tay := make!-Taylor!*(
- v,
- tp,
- if !*taylorkeeporiginal and TayOrig tay
- then simp {car u,mk!*sq TayOrig tay}
- else nil,
- TayFlags tay);
- if null numr singlist then return !*tay2q tay;
- if !*taylorkeeporiginal and TayOrig tay
- then set!-TayOrig(tay,subtrsq(TayOrig tay,singlist));
- return addsq(singlist,!*tay2q tay)
- end;
- symbolic procedure taysimpatan!*(fn,tay);
- begin scalar result,tay1;
- if fn memq '(atan acot)
- then tay := multtaylorsq(tay,simp 'i);
- tay1 := cst!-Taylor!*(1 ./ 1,TayTemplate tay);
- tay := quottaylor(addtaylor(tay1,tay),
- addtaylor(tay1,negtaylor tay));
- result := multsq(taysimplog {'log,tay},1 ./ 2);
- if fn eq 'atan then result := quotsq(result,simp 'i)
- else if fn eq 'acot then result := multsq(result,simp 'i);
- return taysimpsq!* result
- end;
- put('atan,'taylorsimpfn,'taysimpatan);
- put('acot,'taylorsimpfn,'taysimpatan);
- put('atanh,'taylorsimpfn,'taysimpatan);
- put('acoth,'taylorsimpfn,'taysimpatan);
- comment For the logarithm and exponential we use the extension of
- an algorithm quoted by Knuth who shows how to do this for
- series in one expansion variable.
- We extended this to the case of several variables which is
- straightforward except for one point, see below.
- Knuth's algorithm works as follows: Assume you want to compute
- the series W(x) where
- W(x) = log V(x)
- Differentiation of this equation gives
- V'(x)
- W'(x) = ----- , or V'(x) = W'(x)V(x) .
- V(x)
- You make now the ansatz
- -----
- \ n
- W(x) = > W x ,
- / n
- -----
- substitute this into the above equation and compare
- powers of x. This yields the recursion formula
- n-1
- V -----
- n 1 \
- W = ---- - ------ > m W V .
- n V n V / m n-m
- 0 0 -----
- m=0
- The first coefficient must be calculated directly, it is
- W = log V .
- 0 0
- To use this for series in more than one variable you have to
- calculate all partial derivatives: n and m refer then to the
- corresponding component of the multi index. Looking closely
- one finds that there is an ambiguity: the same coefficient
- can be calculated using any of the partial derivatives. The
- only restriction is that the corresponding component of the
- multi index must not be zero, since we have to divide by it.
- We resolve this ambiguity by simply taking the first nonzero
- component.
- The case of the exponential is nearly the same: differentiation
- gives
- W'(x) = V'(x) W(x) ,
- from which we derive the recursion formula
- n-1
- -----
- \ n-m
- W = > --- W V , W = exp V .
- n / m m n-m 0 0
- -----
- m=0
- ;
- symbolic procedure taysimplog u;
- %
- % Special Taylor expansion function for logarithms
- %
- if not (car u eq 'log) or cddr u then confusion 'taysimplog
- else Taylor!:
- begin scalar a0,clist,coefflis,il,l0,l,tay,tp,csing,singterm;
- u := simplogi cadr u;
- if not kernp u then return taysimpsq u;
- u := mvar numr u;
- if not (car u eq 'log) then confusion 'taysimplog;
- u := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p u then return mksq({'log,mk!*sq u},1);
- tay := mvar numr u;
- tp := TayTemplate tay;
- l0 := make!-cst!-powerlist tp;
- %
- % The following relies on the standard ordering of the
- % TayCoeffList.
- %
- l := prune!-coefflist TayCoeffList tay;
- if null l then Taylor!-error!*('not!-a!-unit,'taysimplog);
- %
- % The assumption at this point is that the first term is the one
- % with lowest degree, i.e. dividing by this term yields a series
- % which starts with a constant term.
- %
- if TayCfPl car l neq l0 then
- <<csing := TayCfPl car l;
- l := for each pp in l collect begin scalar newpl;
- newpl := subtr!-degrees(TayCfPl pp,csing);
- if is!-neg!-pl newpl
- then Taylor!-error('not!-a!-unit,'taysimplog)
- else return TayMakeCoeff(newpl,TayCfSQ pp);
- end;
- tp := addto!-all!-TayTpElOrders(
- tp,
- for each nl in csing collect
- - get!-degree nl);
- singterm := simp!* retimes preptaycoeff(csing,tp);
- if !:minusp lnc numr TayCfSq car l
- then <<singterm := negsq singterm;
- l := negtaylor1 l>>>>;
- a0 := TayGetCoeff(l0,l);
- clist := {TayMakeCoeff(l0,simplogi mk!*sq a0)};
- il := if null l then nlist(1,length tp)
- else smallest!-increment l;
- coefflis := makecoeffs0(tp,TpNextList tp,il);
- if not null coefflis
- then for each cc in cdr coefflis do
- begin scalar s,pos,pp,n,n1;
- s := nil ./ 1;
- pos := find!-non!-zero cc;
- n := nth(nth(cc,car pos),cdr pos);
- pp := makecoeffpairs(l0,cc,TayCfPl car l,il);
- for each p in pp do <<
- n1 := nth(nth(car p,car pos),cdr pos);
- s := addsq(s,
- multsq(!*TayExp2q n1,
- multsq(TayGetCoeff(car p,clist),
- TayGetCoeff(cdr p,l))))>>;
- % for each p in pp addsq
- % multsq(!*TayExp2q nth(nth(car p,car pos),cdr pos),
- % multsq(TayGetCoeff(car p,clist),
- % TayGetCoeff(cdr p,l)));
- s := subtrsq(TayGetCoeff(cc,l),quotsq(s,!*TayExp2q n));
- if not null numr s
- then clist := TayMakeCoeff(cc,quotsq(s,a0)) . clist;
- end;
- tay := make!-Taylor!*(
- reversip clist,
- tp,
- if !*taylorkeeporiginal and TayOrig tay
- then simplogi mk!*sq TayOrig tay
- else nil,
- TayFlags tay);
- if null csing then return !*tay2q tay;
- singterm := simplogsq singterm;
- if Taylor!*!-zerop tay then return singterm;
- if !*taylorkeeporiginal and TayOrig tay
- then set!-TayOrig(tay,subtrsq(TayOrig tay,singterm));
- return addsq(singterm,!*tay2q tay)
- end;
- put('log,'taylorsimpfn,'taysimplog);
- symbolic procedure taysimpexp u;
- %
- % Special Taylor expansion function for exponentials
- %
- if not (car u eq 'exp) or cddr u then confusion 'taysimpexp
- else Taylor!:
- begin scalar a0,clist,coefflis,il,l0,l,lm,lp,tay,tp;
- u := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p u
- then return mksq ({'exp,mk!*sq u},1);
- tay := mvar numr u;
- tp := TayTemplate tay;
- l0 := make!-cst!-powerlist tp;
- %
- % The following relies on the standard ordering of the
- % TayCoeffList.
- %
- l := prune!-coefflist TayCoeffList tay;
- if null l then return !*tay2q cst!-Taylor!*(1 ./ 1,tp);
- for each pp in l do
- if is!-neg!-pl TayCfPl pp then lm := pp . lm
- else if not null numr TayCfSq pp then lp := pp . lp;
- lm := reversip lm;
- l := reversip lp;
- if lm
- then lm := simp!* {'exp,
- preptaylor!* make!-Taylor!*(lm,tp,nil,nil)};
- if null l then return lm;
- a0 := TayGetCoeff(l0,l);
- clist := {TayMakeCoeff(l0,simp!* {'exp,mk!*sq a0})};
- il := smallest!-increment l;
- coefflis := makecoeffs0(tp,TpNextList tp,il);
- if not null coefflis
- then for each cc in cdr coefflis do
- begin scalar s,pos,pp,n,n1;
- s := nil ./ 1;
- pos := find!-non!-zero cc;
- n := nth(nth(cc,car pos),cdr pos);
- pp := makecoeffpairs(l0,cc,l0,il);
- for each p in pp do <<
- n1 := nth(nth(car p,car pos),cdr pos);
- s := addsq(s,
- multsq(!*TayExp2q(n - n1),
- multsq(TayGetCoeff(car p,clist),
- TayGetCoeff(cdr p,l))))>>;
- s := subs2!* quotsq(s,!*TayExp2q n);
- if not null numr s
- then clist := TayMakeCoeff(cc,s) . clist
- end;
- clist := reversip clist;
- u := !*tay2q
- make!-Taylor!*(
- clist,
- tp,
- if !*taylorkeeporiginal and TayOrig tay
- then simp {'exp,mk!*sq TayOrig tay}
- else nil,
- TayFlags tay);
- return if null lm then u else multsq(u,lm)
- end;
- put('exp,'taylorsimpfn,'taysimpexp);
- comment The algorithm for the trigonometric functions is also
- derived from their differential equation.
- The simplest case is that of tangent whose equation is
- 2
- tan'(x) = 1 + tan (x) . (*)
- For the others we have
- 2
- cot'(x) = - (1 + cot (x)),
- 2
- tanh'(x) = 1 - tanh (x),
- 2
- coth'(x) = 1 - coth (x) .
- Let T(x) be a Taylor series,
- -----
- \ N
- T(x) = > a x
- / N
- -----
- N=0
- Now, let
- -----
- \ N
- T1(x) = tan T(x) = > b x
- / N
- -----
- N=0
- from which we immediately deduce that b = tan a .
- 0 0
- From (*) we get
- 2
- T1'(x) = (1 + T1(x) ) T'(x) ,
- or, written in terms of the series:
- Inserting this into (*) we get
- ----- / / ----- \ 2 \ -----
- \ N-1 | | \ N | | \ L
- > N b x = | 1 + | > b x | | > L a x
- / N | | / N | | / L
- ----- \ \ ----- / / -----
- N=1 N=0 L=1
- We perform the square on the r.h.s. using Cauchy's rule
- and obtain:
- -----
- \ N-1
- > N b x =
- / N
- -----
- N=1
- N
- / ----- ----- \ -----
- | \ \ N | \ L
- | 1 + > > b b x | > L a x .
- | / / N-M M | / L
- \ ----- ----- / -----
- N=0 M=0 L=1
- Expanding this once again with Cauchy's product rule we get
- -----
- \ N-1
- > N b x =
- / N
- -----
- N=1
- L-1 N
- ----- / ----- ----- \
- \ L-1 | \ \ |
- > x | L a + > > b b (L-N) a | .
- / | L / / N-M M L-N |
- ----- \ ----- ----- /
- L=1 N=0 M=0
- From this we immediately deduce the recursion relation
- L-1 N
- ----- -----
- \ L-N \
- b = a + > ----- a > b b . (**)
- L L / L L-N / N-M M
- ----- -----
- N=0 M=0
- This relation is easily generalized to the case of a
- series in more than one variable, where the same comments
- apply as in the case of log and exp above.
- For the hyperbolic tangent the relation is nearly the same.
- Since its differential equation has a `-' where that of
- tangent has a `+' we simply have to do the same substitution
- in the relation (**). For the cotangent we get an additional
- overall minus sign.
- There is one additional problem to be handled: if the constant
- term of T(x), i.e. T(x0) is a pole of tangent. This can be
- solved quite easily: for a small quantity TAYEPS we calculate
- Te(x) = T(x) + TAYEPS .
- and perform the above calculation for Te(x). Then we recover
- the desired result via the relation
- tan T(x) = tan (Te(x) - TAYEPS)
- tan Te(x) - tan TAYEPS
- = ---------------------------- .
- 1 + tan Te(x) * tan TAYEPS
- For the other functions we have similar relations:
- tanh T(x) = tanh (Te(x) - TAYEPS)
- tanh Te(x) - tanh TAYEPS
- = ------------------------------ ,
- 1 - tanh Te(x) * tanh TAYEPS
- cot T(x) = cot (Te(x) - TAYEPS)
- 1 + cot Te(x) * cot TAYEPS
- = ---------------------------- ,
- cot TAYEPS - cot Te(x)
- coth T(x) = coth (Te(x) - TAYEPS)
- 1 - coth Te(x) * coth TAYEPS
- = ------------------------------ .
- coth Te(x) - coth TAYEPS
- We know that this result is independent of TAYEPS, and we can
- thus evaluate it for any value of TAYEPS.
- Since we further know that T(x0) is a pole of the function in
- question, we can express tan (T(x0) + TAYEPS) as
- 1
- - ------------ ,
- tan TAYEPS
- and similarly all the other possible expressions involving
- TAYEPS can be written in terms of tan TAYEPS and tanh TAYEPS,
- respectively. This makes it possible to just substitute any
- occurrence of tan TAYEPS or tanh TAYEPS by zero, which greatly
- simplifies the final calculation
- ;
- !*!*taylor!-epsilon!*!* := compress '(t a y e p s);
- symbolic procedure taysimptan u;
- %
- % Special Taylor expansion function for circular and hyperbolic
- % tangent and cotangent
- %
- if not (car u memq '(tan cot tanh coth)) or cddr u
- then confusion 'taysimptan
- else Taylor!:
- begin scalar a,a0,clist,coefflis,il,l0,l,poleflag,tay,tp;
- tay := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p tay
- then return mksq({car u,mk!*sq tay},1);
- tay := mvar numr tay;
- tp := TayTemplate tay;
- l0 := make!-cst!-powerlist tp;
- %
- % First we get rid of possible zero coefficients.
- %
- l := prune!-coefflist TayCoeffList tay;
- % if null l then return !*tay2q cst!-Taylor!*(simp!* {car u,0},tp);
- %
- % The following relies on the standard ordering of the
- % TayCoeffList.
- %
- if not null l and is!-neg!-pl TayCfPl car l
- then Taylor!-error('essential!-singularity,car u);
- a0 := TayGetCoeff(l0,l);
- il := if null l then nlist(1,length tp)
- else smallest!-increment l;
- %
- %%% handle poles of function
- %
- a := quotsq(a0,simp 'pi);
- if car u memq '(tanh coth) then a := subs2!* multsq(a,simp 'i);
- if car u memq '(tan tanh) and
- denr(a := multsq(a,simp '2)) = 1 and
- fixp (a := numr a) and not evenp a
- or car u memq '(cot coth) and denr a = 1 and
- (null (a := numr a) or fixp a)
- then <<
- %
- % OK, now we are at a pole, so we add a small quantity, compute
- % the series and use the addition formulas to get the real
- % result.
- %
- poleflag := t;
- a0 := if car u eq 'tan
- then negsq invsq simp!* {'tan,!*!*taylor!-epsilon!*!*}
- else if car u eq 'tanh
- then invsq simp!* {'tanh,!*!*taylor!-epsilon!*!*}
- else if car u eq 'cot
- then invsq simp!* {'tan,!*!*taylor!-epsilon!*!*}
- else invsq simp!* {'tanh,!*!*taylor!-epsilon!*!*};
- clist := {TayMakeCoeff(l0,a0)};
- >>
- else clist := {TayMakeCoeff(l0,simp!* {car u,mk!*sq a0})};
- %
- coefflis := makecoeffs0(tp,TpNextList tp,il);
- if not null coefflis
- then for each cc in cdr coefflis do
- begin scalar cf,s,pos,x,y,n,n1;
- s := nil ./ 1;
- pos := find!-non!-zero cc;
- n := nth(nth(cc,car pos),cdr pos);
- for each p in makecoeffpairs(l0,cc,l0,il) do <<
- x := reversip makecoeffpairs1(l0,car p,l0,il);
- y := nil ./ 1;
- for each z in x do
- y := addsq(y,multsq(TayGetCoeff(car z,clist),
- TayGetCoeff(cdr z,clist)));
- n1 := nth(nth(car p,car pos),cdr pos);
- s := addsq(s,
- multsq(!*TayExp2q(n - n1),
- multsq(y,TayGetCoeff(cdr p,l))))>>;
- cf := quotsq(s,!*TayExp2q n);
- if car u memq '(tanh coth) then cf := negsq cf;
- cf := addsq(TayGetCoeff(cc,l),cf);
- if null numr cf then return; % short cut for efficiency
- if car u eq 'cot then cf := negsq cf;
- clist := TayMakeCoeff(cc,cf) . clist
- end;
- a := make!-Taylor!*(reversip clist,tp,nil,nil);
- %
- % Construct ``real'' series in case of pole
- %
- if poleflag then begin scalar x;
- x := if car u eq 'cot
- then cst!-Taylor!*(
- invsq simp {'tan,!*!*taylor!-epsilon!*!*},tp)
- else if car u eq 'coth
- then cst!-Taylor!*(
- invsq simp {'tanh,!*!*taylor!-epsilon!*!*},tp)
- else cst!-Taylor!*(
- simp {car u,!*!*taylor!-epsilon!*!*},tp);
- if car u eq 'tan then
- a := quottaylor(addtaylor(a,negtaylor x),
- addtaylor(cst!-taylor!*(1 ./ 1,tp),
- multtaylor(a,x)))
- else if car u eq 'cot then
- a := quottaylor(addtaylor(multtaylor(a,x),
- cst!-taylor!*(1 ./ 1,tp)),
- addtaylor(x,negtaylor a))
- else if car u eq 'tanh then
- a := quottaylor(addtaylor(a,negtaylor x),
- addtaylor(cst!-taylor!*(1 ./ 1,tp),
- negtaylor multtaylor(a,x)))
- else if car u eq 'coth then
- a := quottaylor(addtaylor(multtaylor(a,x),
- cst!-taylor!*(-1 ./ 1,tp)),
- addtaylor(x,negtaylor a));
-
- if not (a freeof !*!*taylor!-epsilon!*!*)
- then set!-TayCoeffList(a,
- for each pp in TayCoeffList a collect
- TayMakeCoeff(TayCfPl pp,
- subsq(TayCfSq pp,
- {!*!*taylor!-epsilon!*!* . 0})));
- end;
- %
- if !*taylorkeeporiginal and TayOrig tay
- then set!-TayOrig(a,simp {car u,mk!*sq TayOrig tay});
- set!-Tayflags(a,TayFlags tay);
- return !*tay2q a
- end;
- put('tan,'taylorsimpfn,'taysimptan);
- put('cot,'taylorsimpfn,'taysimptan);
- put('tanh,'taylorsimpfn,'taysimptan);
- put('coth,'taylorsimpfn,'taysimptan);
- comment For the circular sine and cosine and their reciprocals
- we calculate the exponential and use it via the formulas
- exp(+I*x) - exp(-I*x)
- sin x = ----------------------- ,
- 2
- exp(+I*x) + exp(-I*x)
- cos x = ----------------------- ,
- 2
- etc. To avoid clumsy expressions we separate the constant term
- of the argument,
- T(x) = a0 + T1(x),
- and use the addition theorems which give
- 1
- sin T(x) = - exp(+I*T1(x)) * (sin a0 - I*cos a0) +
- 2
- 1
- - exp(-I*T1(x)) * (sin a0 + I*cos a0) ,
- 2
-
- 1
- cos T(x) = - exp(+I*T1(x)) * (cos a0 + I*sin a0) +
- 2
- 1
- - exp(-I*T1(x)) * (cos a0 - I*sin a0) .
- 2
- ;
- symbolic procedure taysimpsin u;
- %
- % Special Taylor expansion function for circular sine, cosine,
- % and their reciprocals
- %
- if not (car u memq '(sin cos sec csc)) or cddr u
- then confusion 'taysimpsin
- else Taylor!:
- begin scalar l,tay,result,tp,i1,l0,a0,a1,a2;
- tay := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p tay
- then return mksq({car u,mk!*sq tay},1);
- tay := mvar numr tay;
- tp := TayTemplate tay;
- l0 := make!-cst!-powerlist tp;
- l := prune!-coefflist TayCoeffList tay;
- % if null l then return !*tay2q cst!-Taylor!*(simp!* {car u,0},tp);
- % if is!-neg!-pl TayCfPl car l
- % then Taylor!-error('essential!-singularity,car u);
- a0 := TayGetCoeff(l0,l);
- %
- % make constant term to 0
- %
- i1 := simp 'i;
- if not null numr a0
- then tay := addtaylor(tay,cst!-Taylor!*(negsq a0,tp));
- result := taysimpexp{'exp,multtaylor(tay,cst!-Taylor!*(i1,tp))};
- a1 := simp!* {'sin,mk!*sq a0} . simp!* {'cos,mk!*sq a0};
- if car u memq '(sin csc) then <<
- a2 := addsq(car a1,multsq(i1,cdr a1));
- a1 := addsq(car a1,negsq multsq(i1,cdr a1));
- >>
- else <<
- a2 := addsq(cdr a1,negsq multsq(i1,car a1));
- a1 := addsq(cdr a1,multsq(i1,car a1));
- >>;
- result := multsq(addsq(multsq(result,a1),
- multsq(taysimpsq!* invsq result,a2)),
- 1 ./ 2);
- if car u memq '(sec csc) then result := invsq result;
- return taysimpsq!* result
- end;
- put('sin,'taylorsimpfn,'taysimpsin);
- put('cos,'taylorsimpfn,'taysimpsin);
- put('sec,'taylorsimpfn,'taysimpsin);
- put('csc,'taylorsimpfn,'taysimpsin);
- comment For the hyperbolic sine and cosine and their reciprocals
- we calculate the exponential and use it via the formulas
- exp(+x) - exp(-x)
- sinh x = ------------------- ,
- 2
- exp(+x) + exp(-x)
- cosh x = ------------------- ,
- 2
- etc. To avoid clumsy expressions we separate the constant term
- of the argument,
- T(x) = a0 + T1(x),
- and use the addition theorems which give
- 1
- sinh T(x) = - exp(+T1(x)) * (sinh a0 + cosh a0) +
- 2
- 1
- - exp(-T1(x)) * (sinh a0 - cosh a0) ,
- 2
-
- 1
- cosh T(x) = - exp(+T1(x)) * (cosh a0 + sinh a0) +
- 2
- 1
- - exp(-T1(x)) * (cosh a0 - sinh a0) .
- 2
- ;
- symbolic procedure taysimpsinh u;
- %
- % Special Taylor expansion function for circular sine, cosine,
- % and their reciprocals
- %
- if not (car u memq '(sinh cosh sech csch)) or cddr u
- then confusion 'taysimpsin
- else Taylor!:
- begin scalar l,tay,result,tp,l0,a0,a1,a2;
- tay := taysimpsq simp!* cadr u;
- if not Taylor!-kernel!-sq!-p tay
- then return mksq({car u,mk!*sq tay},1);
- tay := mvar numr tay;
- tp := TayTemplate tay;
- l0 := make!-cst!-powerlist tp;
- l := prune!-coefflist TayCoeffList tay;
- % if null l then return !*tay2q cst!-Taylor!*(simp!* {car u,0},tp);
- % if is!-neg!-pl TayCfPl car l
- % then Taylor!-error('essential!-singularity,car u);
- a0 := TayGetCoeff(l0,l);
- %
- % make constant term to 0
- %
- if not null numr a0
- then tay := addtaylor(tay,cst!-Taylor!*(negsq a0,tp));
- result := taysimpexp{'exp,tay};
- a1 := simp!* {'sinh,mk!*sq a0} . simp!* {'cosh,mk!*sq a0};
- if car u memq '(sinh csch) then <<
- a2 := addsq(car a1,cdr a1);
- a1 := subtrsq(car a1,cdr a1);
- >>
- else <<
- a2 := addsq(cdr a1,car a1);
- a1 := subtrsq(cdr a1,car a1);
- >>;
- result := multsq(addsq(multsq(result,a2),
- multsq(taysimpsq!* invsq result,a1)),
- 1 ./ 2);
- if car u memq '(sech csch) then result := invsq result;
- return taysimpsq!* result
- end;
- put('sinh, 'taylorsimpfn, 'taysimpsinh);
- put('cosh, 'taylorsimpfn, 'taysimpsinh);
- put('sech, 'taylorsimpfn, 'taysimpsinh);
- put('csch, 'taylorsimpfn, 'taysimpsinh);
- comment Support for the integration of Taylor kernels.
- Unfortunately, with the current interface, only Taylor kernels
- on toplevel can be treated successfully.
- The way it is down means stretching certain interfaces beyond
- what they were designed for...but it works!
- First we add a rule that replaces a call to INT with a Taylor
- kernel as argument by a call to TAYLORINT, then we define
- REVALTAYLORINT as simplification function for that;
- algebraic let {
- int(symbolic algebraic(taylor!*(~x,~y,~z,~w)),~u)
- => taylorint(~x,~y,~z,~w,~u),
- int(log(~u)^~~n * symbolic algebraic(taylor!*(~x,~y,~z,~w)),~u)
- => log(u)^n * int(symbolic('(taylor!* x y z w)),u)
- - int(log(u)^(n-1)
- * taylorcombine(int(symbolic('(taylor!* x y z w)),u)/u),u),
- int(~x,~y) => taylorint1(~x,~y)
- when not symbolic algebraic(~x freeof 'Taylor!*)
- };
- put('taylorint1, 'psopfn, 'revaltaylorint1);
- symbolic procedure revaltaylorint1 x;
- begin scalar u,v;
- u := car x;
- v := cadr x;
- if Taylor!*p u then return revaltaylorint append(cdr u,{v});
- u := reval taylorcombine u;
- if Taylor!*p u then return revaltaylorint append(cdr u,{v});
- if not atom u
- then if car u memq '(plus minus difference)
- then return
- reval (car u . for each term in cdr u collect
- {'int,term,v});
- lprim "Converting Taylor kernels to standard representation";
- return aeval {'int,taylortostandard car x,v}
- end;
- put('taylorint, 'psopfn, 'revaltaylorint);
- symbolic procedure revaltaylorint u;
- begin scalar taycfl, taytp, tayorg, tayflgs, var;
- taycfl := car u;
- taytp := cadr u;
- tayorg := caddr u;
- tayflgs := cadddr u;
- var := car cddddr u;
- if null (var member TayTpVars taytp)
- then return mk!*sq !*tay2q
- make!-Taylor!*(
- for each pp in taycfl collect
- TayCfPl pp . simp!* {'int,mk!*sq TayCfSq pp,var},
- taytp,
- if not null tayorg
- then simp!* {'int,mk!*sq tayorg,var}
- else nil,
- nil)
- else return mk!*sq
- ((if null car result then !*tay2q cdr result
- else addsq(car result,!*tay2q cdr result))
- where result := inttaylorwrttayvar1(taycfl,taytp,var))
- end;
- endmodule;
- end;
|