From: Richard Kreckel Date: Mon, 29 Nov 1999 22:50:42 +0000 (+0000) Subject: - changed function::diff() to be more tolerant by checking first if the X-Git-Tag: release_0-5-0~105 X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=commitdiff_plain;h=be0485a03e9886496eeb7e8cdc2cc5c95b848632;hp=a87e6ee6d794b99dcf3946e7dde969edafeb3295 - changed function::diff() to be more tolerant by checking first if the nth argument when differentiated is non-zero and *then* building the sum. - added support for overloaded polygamma functions psi(x) and psi(n,x). - changed return code of atan2_diff to be somewhat simpler and adjusted check/differentiation.cpp to account for this. --- diff --git a/check/differentiation.cpp b/check/differentiation.cpp index 611342d0..0d963fed 100644 --- a/check/differentiation.cpp +++ b/check/differentiation.cpp @@ -234,10 +234,16 @@ static unsigned differentiation5(void) pow(y*b+pow(y,2)*x+a,-2)*pow(y,2))* pow(1+pow(a*x+b+y*pow(x,2),2)*pow(y*b+pow(y,2)*x+a,-2),-1); */ + /* d = pow(1+pow(a*x+b+y*pow(x,2),2)*pow(y*b+pow(y,2)*x+a,-2),-1) *pow(y*b+pow(y,2)*x+a,-1)*(a+2*y*x) +pow(y,2)*(-a*x-b-y*pow(x,2))* pow(pow(y*b+pow(y,2)*x+a,2)+pow(a*x+b+y*pow(x,2),2),-1); + */ + d = pow(y,2)*pow(pow(b+y*pow(x,2)+x*a,2)+pow(y*b+pow(y,2)*x+a,2),-1)* + (-b-y*pow(x,2)-x*a)+ + pow(pow(b+y*pow(x,2)+x*a,2)+pow(y*b+pow(y,2)*x+a,2),-1)* + (y*b+pow(y,2)*x+a)*(2*y*x+a); result += check_diff(e, x, d); return result; diff --git a/ginac/diff.cpp b/ginac/diff.cpp index 7b4d489b..2661fddb 100644 --- a/ginac/diff.cpp +++ b/ginac/diff.cpp @@ -175,17 +175,22 @@ ex power::diff(symbol const & s) const ex function::diff(symbol const & s) const { exvector new_seq; - - if (serial == function_index_Order) { - + + if (serial==function_index_Order) { // Order Term function only differentiates the argument return Order(seq[0].diff(s)); - } else { - // Chain rule + ex arg_diff; for (unsigned i=0; i!=seq.size(); i++) { - new_seq.push_back(mul(pdiff(i), seq[i].diff(s))); + arg_diff = seq[i].diff(s); + // We apply the chain rule only when it makes sense. This is not + // just for performance reasons but also to allow functions to + // throw when differentiated with respect to one of its arguments + // without running into trouble with our automatic full + // differentiation: + if (!arg_diff.is_zero()) + new_seq.push_back(mul(pdiff(i), arg_diff)); } } return add(new_seq); diff --git a/ginac/inifcns.h b/ginac/inifcns.h index ee737818..725c1ee7 100644 --- a/ginac/inifcns.h +++ b/ginac/inifcns.h @@ -87,8 +87,16 @@ DECLARE_FUNCTION_1P(zeta) DECLARE_FUNCTION_1P(gamma) /** Psi-function (aka polygamma-function). */ +extern unsigned function_index_psi1; +inline function psi(ex const & p1) { + return function(function_index_psi1, p1); +} +extern unsigned function_index_psi2; +inline function psi(ex const & p1, ex const & p2) { + return function(function_index_psi2, p1, p2); +} //DECLARE_FUNCTION_1P(psi) -DECLARE_FUNCTION_2P(psi) +//DECLARE_FUNCTION_2P(psi) /** Factorial function. */ DECLARE_FUNCTION_1P(factorial) diff --git a/ginac/inifcns_gamma.cpp b/ginac/inifcns_gamma.cpp index bb3a74e0..a208592f 100644 --- a/ginac/inifcns_gamma.cpp +++ b/ginac/inifcns_gamma.cpp @@ -46,19 +46,19 @@ static ex gamma_eval(ex const & x) { if (x.info(info_flags::numeric)) { // trap integer arguments: - if ( x.info(info_flags::integer) ) { + if (x.info(info_flags::integer)) { // gamma(n+1) -> n! for postitive n - if ( x.info(info_flags::posint) ) { + if (x.info(info_flags::posint)) { return factorial(ex_to_numeric(x).sub(numONE())); } else { return numZERO(); // Infinity. Throw? What? } } // trap half integer arguments: - if ( (x*2).info(info_flags::integer) ) { + if ((x*2).info(info_flags::integer)) { // trap positive x=(n+1/2) // gamma(n+1/2) -> Pi^(1/2)*(1*3*..*(2*n-1))/(2^n) - if ( (x*2).info(info_flags::posint) ) { + if ((x*2).info(info_flags::posint)) { numeric n = ex_to_numeric(x).sub(numHALF()); numeric coefficient = doublefactorial(n.mul(numTWO()).sub(numONE())); coefficient = coefficient.div(numTWO().power(n)); @@ -75,7 +75,7 @@ static ex gamma_eval(ex const & x) } return gamma(x).hold(); } - + static ex gamma_evalf(ex const & x) { BEGIN_TYPECHECK @@ -89,7 +89,7 @@ static ex gamma_diff(ex const & x, unsigned diff_param) { GINAC_ASSERT(diff_param==0); - return psi(exZERO(),x)*gamma(x); // diff(log(gamma(x)),x)==psi(0,x) + return psi(x)*gamma(x); // diff(log(gamma(x)),x)==psi(x) } static ex gamma_series(ex const & x, symbol const & s, ex const & point, int order) @@ -108,17 +108,57 @@ REGISTER_FUNCTION(gamma, gamma_eval, gamma_evalf, gamma_diff, gamma_series); // Psi-function (aka polygamma-function) ////////// +/** Evaluation of polygamma-function psi(x). + * Somebody ought to provide some good numerical evaluation some day... */ +static ex psi1_eval(ex const & x) +{ + if (x.info(info_flags::numeric)) { + // do some stuff... + } + return psi(x).hold(); +} + +static ex psi1_evalf(ex const & x) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + END_TYPECHECK(psi(x)) + + return psi(ex_to_numeric(x)); +} + +static ex psi1_diff(ex const & x, unsigned diff_param) +{ + GINAC_ASSERT(diff_param==0); + + return psi(exONE(), x); +} + +static ex psi1_series(ex const & x, symbol const & s, ex const & point, int order) +{ + throw(std::logic_error("Nobody told me how to series expand the psi function. :-(")); +} + +unsigned function_index_psi1 = function::register_new("psi", psi1_eval, psi1_evalf, psi1_diff, psi1_series); + +////////// +// Psi-functions (aka polygamma-functions) psi(0,x)==psi(x) +////////// + /** Evaluation of polygamma-function psi(n,x). * Somebody ought to provide some good numerical evaluation some day... */ -static ex psi_eval(ex const & n, ex const & x) +static ex psi2_eval(ex const & n, ex const & x) { + // psi(0,x) -> psi(x) + if (n.is_zero()) + return psi(x).hold(); if (n.info(info_flags::numeric) && x.info(info_flags::numeric)) { // do some stuff... } return psi(n, x).hold(); } - -static ex psi_evalf(ex const & n, ex const & x) + +static ex psi2_evalf(ex const & n, ex const & x) { BEGIN_TYPECHECK TYPECHECK(n,numeric) @@ -128,18 +168,23 @@ static ex psi_evalf(ex const & n, ex const & x) return psi(ex_to_numeric(n), ex_to_numeric(x)); } -static ex psi_diff(ex const & n, ex const & x, unsigned diff_param) +static ex psi2_diff(ex const & n, ex const & x, unsigned diff_param) { - GINAC_ASSERT(diff_param==0); + GINAC_ASSERT(diff_param<2); + if (diff_param==0) { + // d/dn psi(n,x) + throw(std::logic_error("cannot diff psi(n,x) with respect to n")); + } + // d/dx psi(n,x) return psi(n+1, x); } -static ex psi_series(ex const & n, ex const & x, symbol const & s, ex const & point, int order) +static ex psi2_series(ex const & n, ex const & x, symbol const & s, ex const & point, int order) { - throw(std::logic_error("Nobody told me how to series expand the psi function. :-(")); + throw(std::logic_error("Nobody told me how to series expand the psi functions. :-(")); } -REGISTER_FUNCTION(psi, psi_eval, psi_evalf, psi_diff, psi_series); +unsigned function_index_psi2 = function::register_new("psi", psi2_eval, psi2_evalf, psi2_diff, psi2_series); } // namespace GiNaC diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp index 70eccdce..db502ca9 100644 --- a/ginac/inifcns_trans.cpp +++ b/ginac/inifcns_trans.cpp @@ -468,10 +468,10 @@ static ex atan2_diff(ex const & y, ex const & x, unsigned diff_param) if (diff_param==0) { // d/dy atan(y,x) - return pow(x*(1+y*y/(x*x)),-1); + return x*pow(pow(x,2)+pow(y,2),-1); } // d/dx atan(y,x) - return -y*pow(x*x+y*y,-1); + return -y*pow(pow(x,2)+pow(y,2),-1); } REGISTER_FUNCTION(atan2, atan2_eval, atan2_evalf, atan2_diff, NULL); diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp index bb2762a2..1cc1fa69 100644 --- a/ginac/numeric.cpp +++ b/ginac/numeric.cpp @@ -1084,6 +1084,14 @@ numeric gamma(numeric const & x) /** The psi function (aka polygamma function). * This is only a stub! */ +numeric psi(numeric const & x) +{ + clog << "psi(): Does anybody know good way to calculate this numerically?" << endl; + return numeric(0); +} + +/** The psi functions (aka polygamma functions). + * This is only a stub! */ numeric psi(numeric const & n, numeric const & x) { clog << "psi(): Does anybody know good way to calculate this numerically?" << endl; diff --git a/ginac/numeric.h b/ginac/numeric.h index 88b7d953..13c790fc 100644 --- a/ginac/numeric.h +++ b/ginac/numeric.h @@ -241,6 +241,7 @@ numeric acosh(numeric const & x); numeric atanh(numeric const & x); numeric zeta(numeric const & x); numeric gamma(numeric const & x); +numeric psi(numeric const & x); numeric psi(numeric const & n, numeric const & x); numeric factorial(numeric const & n); numeric doublefactorial(numeric const & n);