diff --git a/src/cpp/cseval/cseval.hpp b/src/cpp/cseval/cseval.hpp index 258d7460..a416f5f6 100644 --- a/src/cpp/cseval/cseval.hpp +++ b/src/cpp/cseval/cseval.hpp @@ -209,7 +209,6 @@ right path of the derivative"); // exponentiation for the computation of the derivative (left path) static Real _pow1(Real a, Real b) { return (b * _pow(a, b - ONE)); } // exponentiation for the computation of the derivative (right path) - // TODO test log() static Real _pow2(Real a, Real b) { return (_log(a) * _pow(a, b)); } //- general static methods @@ -282,7 +281,6 @@ the natural logarithm derivative"); } // "sqrt" - square root static Real _sqrt(Real a) { return sqrt(a); } - // TODO test _sqrt_d() // "sqrt" for the derivative static Real _sqrt_d(Real a, Real) { if (sqrt(a) == ZERO) { diff --git a/src/cpp/cseval/cseval_complex.hpp b/src/cpp/cseval/cseval_complex.hpp index 535e2451..b61425e4 100644 --- a/src/cpp/cseval/cseval_complex.hpp +++ b/src/cpp/cseval/cseval_complex.hpp @@ -210,7 +210,6 @@ right path of the derivative"); // exponentiation for the computation of the derivative (left path) static Complex _pow1(Complex a, Complex b) { return (b * _pow(a, b - ONE)); } // exponentiation for the computation of the derivative (right path) - // TODO test log() static Complex _pow2(Complex a, Complex b) { return (_log(a) * _pow(a, b)); } //- general static methods @@ -283,7 +282,6 @@ the natural logarithm derivative"); } // "sqrt" - square root static Complex _sqrt(Complex a) { return sqrt(a); } - // TODO test _sqrt_d() // "sqrt" for the derivative static Complex _sqrt_d(Complex a, Complex) { if (sqrt(a) == ZERO) { diff --git a/tests/test_derivative_coverage.py b/tests/test_derivative_coverage.py new file mode 100644 index 00000000..fa4073c3 --- /dev/null +++ b/tests/test_derivative_coverage.py @@ -0,0 +1,45 @@ +"""Regression: derivative-of-^ uses log(), derivative-of-sqrt fires. + +Closes TODOs: + src/cpp/cseval/cseval.hpp:212 (// TODO test log()) + src/cpp/cseval/cseval.hpp:285 (// TODO test _sqrt_d()) + src/cpp/cseval/cseval_complex.hpp:213 (// TODO test log()) + src/cpp/cseval/cseval_complex.hpp:286 (// TODO test _sqrt_d()) + +The `^` derivative's right path is `_pow2(a, b) = log(a) * pow(a, b)`, +which is only reached when the exponent is itself a function of the +differentiation variable. The `_sqrt_d` path is reached for d(sqrt(x))/dx. +Both fire on the real and complex evaluation paths. +""" + +from formula import Solver + + +def test_pow_derivative_via_log_real(): + # d(x^y)/dy = log(x) * x^y. At x=2, y=3: log(2)*8 = 5.5451774444795625... + result = Solver("x^y", precision=24)( + {"x": "2", "y": "3"}, derivative="y" + ) + assert result.startswith("5.545177444479562475337856") + + +def test_pow_derivative_via_log_complex(): + # Same identity through the complex path. The presence of 'i' in the + # expression forces complex evaluation, so _pow2 in cseval_complex.hpp + # runs instead of the real twin. + result = Solver("(2+i*0)^y", precision=24)( + {"y": "3"}, derivative="y" + ) + assert result.startswith("5.5451774444795624753378") + + +def test_sqrt_derivative_real(): + # d(sqrt(x))/dx = 1/(2*sqrt(x)). At x=4: 1/(2*2) = 0.25. + result = Solver("sqrt(x)", precision=24)({"x": "4"}, derivative="x") + assert result == "0.25" + + +def test_sqrt_derivative_complex(): + # Same identity through the complex path (forced by 'i' in the expression). + result = Solver("sqrt(x+i*0)", precision=24)({"x": "4"}, derivative="x") + assert result.startswith("0.25")