Skip to content

TST: kelvin: add a Wronskian identity test - #236

Open
EazyHood wants to merge 3 commits into
scipy:mainfrom
EazyHood:test-kelvin-wronskian
Open

TST: kelvin: add a Wronskian identity test#236
EazyHood wants to merge 3 commits into
scipy:mainfrom
EazyHood:test-kelvin-wronskian

Conversation

@EazyHood

@EazyHood EazyHood commented Aug 4, 2026

Copy link
Copy Markdown

Follows up on the Wronskian test offered in gh-232, which @steppi said he'd be happy to see.

What it checks

The Kelvin functions satisfy

x * (Be*Kep - Bep*Ke) == -1

with Be = ber + i*bei, Ke = ker + i*kei, and Bep, Kep their derivatives — exactly the four values xsf::kelvin() returns. Its real part is (ber*kerp - berp*ker) - (bei*keip - beip*kei) and its imaginary part is (ber*keip - berp*kei) + (bei*kerp - beip*ker), so a single check exercises all eight functions.

I derived it by searching bilinear combinations against mpmath rather than quoting it: over x in [0.05, 25] at 50 digits the largest deviation is 1.4e-51, which is mpmath's own rounding.

It needs no reference table — the functions are checked against each other. That is why it does not depend on how the |x| < 10 branch point question in gh-232 is resolved.

What it measures on the current implementation

Sweeping 52 points against scipy 1.17.1:

x |residual|
0.001 0
0.5 0
5.0 7.1e-14
9.9 8.2e-11
10.0 7.4e-13
20.0 2.2e-16
50.0 0

The worst point in the whole sweep sits just below the |x| < 10 branch point, and crossing it improves by ~111x. That is the claim gh-232 makes, arrived at without mpmath and without any reference values of mine — it is the library disagreeing with itself.

On the tolerance

atol = 1e-9 passes today with about two orders of margin, so this lands as a non-regression test rather than a failing assertion. At 1e-12 it fails at x = 9.9 on current main. I chose the looser bound deliberately so the test is mergeable independently of the branch-point work; if you would rather it fail loudly and block until that is fixed, say so and I will tighten it.

What I have not done

I have not compiled this. Catch2 3, Arrow and Parquet are not available on the machine I measured from, so the numbers above are verified but the build is not. It goes in tests/xsf_tests/ rather than tests/scipy_special_tests/ because it needs no parquet tables, and CMakeLists.txt picks it up through the existing file(GLOB TEST_SOURCES "*/test_*.cpp") — no build-system change. If CI finds a compile error I will fix it promptly; the one thing I would guess at is whether CAPTURE() prints std::complex<double>, which is diagnostic only.


AI disclosure: prepared with AI assistance (Claude Opus 5 via Claude Code). The identity and every figure above were measured, and I am responsible for the change as submitted.

x * (Be*Kep - Bep*Ke) == -1, with Be = ber + i*bei, Ke = ker + i*kei and Bep,
Kep their derivatives -- exactly what xsf::kelvin() returns. One check covers all
eight functions, and it needs no reference table, so it stays valid whatever is
decided about the |x| < 10 branch point in scipygh-232.

Verified against mpmath at 50 digits over x in [0.05, 25]: largest deviation
1.4e-51. On the current implementation the worst residual over the 20 sampled
points is 8.2e-11, at x = 9.9.
@github-actions github-actions Bot added the Maintenance Items related to regular maintenance tasks label Aug 4, 2026
The list fits on one 117-column line; splitting it at 70 was below the project's
120-column limit and clang-format packs it.
Comment on lines +15 to +16
// Verified against mpmath at 50 digits for x in [0.05, 25]: the largest deviation
// is 1.4e-51, i.e. mpmath's own rounding.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this comment refer to?

Comment on lines +17 to +20
//
// This needs no reference table -- the eight functions are checked against each
// other -- so it stays valid whatever is decided about the |x| < 10 branch point
// discussed in gh-232.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//
// This needs no reference table -- the eight functions are checked against each
// other -- so it stays valid whatever is decided about the |x| < 10 branch point
// discussed in gh-232.

The mpmath line described a separate check, not anything this test does, and the
scipygh-232 note was removed per the review suggestion.
@EazyHood

Copy link
Copy Markdown
Author

Both removed. The mpmath line described a separate check I ran while writing the test, not
anything the test does - the Wronskian is self-checking, so that number didn't belong in the
header.

The workflows on this PR are all sitting in action_required and have never run, so there is no
CI signal on it yet. Could someone approve the run when convenient?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Maintenance Items related to regular maintenance tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants