From 80b83dd8f9a2e081489b15092b4ab28fccec70da Mon Sep 17 00:00:00 2001 From: Ivan Ergunov Date: Wed, 20 May 2026 00:50:05 +0200 Subject: [PATCH] =?UTF-8?q?test:=20derivative-of-^=20via=20log()=20and=20d?= =?UTF-8?q?erivative-of-sqrt=20=E2=80=94=20real=20+=20complex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds regression coverage for the four derivative paths that carried '// TODO test ...' comments: _pow2 (real) cseval.hpp:212 — d(x^y)/dy = log(x) * x^y _pow2 (complex) cseval_complex.hpp:213 _sqrt_d (real) cseval.hpp:285 — d(sqrt(x))/dx = 1/(2*sqrt(x)) _sqrt_d (complex) cseval_complex.hpp:286 Tests in tests/test_derivative_coverage.py exercise each path with a value that yields a clean expected result (e.g. log(2)*8 ≈ 5.5451…, 1/(2*2) = 0.25). The complex twins use expressions containing 'i' to force evaluation through cseval_complex. After the tests pin the behavior, the four '// TODO test ...' comments are deleted from the C++ source. Full suite 392/392 (+4 new), 3 xfailed unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/cpp/cseval/cseval.hpp | 2 -- src/cpp/cseval/cseval_complex.hpp | 2 -- tests/test_derivative_coverage.py | 45 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 tests/test_derivative_coverage.py 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")