Increase robustness of zero-finding and document the valid range of usage#28
Conversation
|
I submitted this PR a little too early. All tests ran successfully on my machine where Int === Int64, but I see some have failed in CI on x86 machines, where Int === Int32, and the @test_broken tests are actually no longer broken. I also now see from the comments preceding the "high nu" test set that Issue #27 overlaps with Issue #10. I'll modify this PR to replace the @test_broken tests to @test after which I think everything should work ok. |
|
Edit: Changing this to a WIP (Work In Progress) PR since the problem still occurs for even higher |
|
Ok, I've implemented an asymptotic formula from DLMF that is appropriate for large nu and small n. Now the first ten zeros of any of the four treated functions are returned correctly for any positive nu value. All zeros are returned correctly for nu less than or equal to at least 150. This corrects the problem mentioned in this comment to Issue #10. Here is an example of finding the correct first 25 zeros for the derivative of a Bessel Y function of order 150:
And here is an example showing that the first 10 zeros are correctly found for a ridiculously large value of
|
|
Friendly bump (maybe reviewing this would make a good new year's resolution? 😉). |
|
@jlapeyre Could you please review? Or is there anyone else who could be asked to review? TIA |
|
After multiple friendly bumps over several months, I've gotten zero responses. @DilumAluthge Is there anyone else in JuliaMath who could possibly review this PR? |
|
Hi @simonp0420, I'd be happy to help. Let me see if I can recruit someone to review. |
|
In the meantime, could you update the PR title to be a bit more descriptive? |
|
Thanks, @simonp0420, for all the work. And thanks @DilumAluthge for the ping. |
| function bessel_deriv_zero_asymptotic(nu_in::Real, n::Integer, kind=1) | ||
| # Reference: https://dlmf.nist.gov/10.21.E20 | ||
| nu = abs(nu_in) | ||
| if (nu ≥ 33 && n ≤ 10) || (nu ≥ 30 && n ≤ 9) || (nu ≥ 26 && n ≤ 8) || (nu ≥ 25 && n ≤ 7) |
There was a problem hiding this comment.
could this be if nu>3n? or something similar?
There was a problem hiding this comment.
Yes, thanks. Will replace with (nu ≥ 25) && (nu ≥ 3.25 * n)
| package. Each field in the named tuple consists of a tuple of `n` increasingly negative values. Here `n` | ||
| is a small integer, currently 10. | ||
| """ | ||
| @inline function airy_zeros() |
There was a problem hiding this comment.
where do these numbers come from?
There was a problem hiding this comment.
I'm embarassed to admit that were obtained by first plotting the airy functions, then using Roots.find_zero with a seed value obtained for each root by visually inspecting the plot. Here is some validation:
julia> using FunctionZeros: FunctionZeros as fz
[ Info: Precompiling FunctionZeros [b21f74c0-b399-568f-9643-d20f4fa2c814](cache misses: incompatible header (9))
Precompiling FunctionZeros finished.
7 dependencies successfully precompiled in 8 seconds. 19 already precompiled.
julia> (; ai, bi, aiprime, biprime) = fz.airy_zeros();
julia> using SpecialFunctions
julia> maximum(x -> abs(airyai(x)), ai)
2.0278943050169084e-15
julia> maximum(x -> abs(airybi(x)), bi)
1.2350493860255089e-15
julia> maximum(x -> abs(airyaiprime(x)), aiprime)
2.905936767899529e-15
julia> maximum(x -> abs(airybiprime(x)), biprime)
4.585753687468294e-15There was a problem hiding this comment.
We should definitely do the calculation of the roots in BigFloat precision (and then round that down to Float64). (possibly using mathematica if Special Functions doesn't support it). These functions aren't that useful if they aren't hitting the true zeros.
There was a problem hiding this comment.
I'll push back gently on this...
I had considered obtaining these to higher precision when I wrote the function, but since this function is not exported nor externally documented, and its used only for obtaining approximate starting values for finding Bessel function roots, I didn't think that it was necessary. I figured that eventually, someone will write a proper package to compute any number of airy function zeros to arbitrary precision. Perhaps it's sufficient to state in the docstring that the zeros are only supplied to Float64 accuracy.
If you still think it's important to supply BigFloat precision for the airy function zeros here then I'll implement it.
There was a problem hiding this comment.
in that case, this is probably fine. I thought that these values would be directly affecting the output.
There was a problem hiding this comment.
I would have trouble implementing it anyway, since I don't have Mathematica and I just found out that SpecialFunctions.airybi is erroring for negative BigFloat arguments.
| -7.940178689168584, -9.019583358794248, -10.037696334908555, -11.00646266771229, | ||
| -11.934261645014844, -12.82725830917722) | ||
| #return (; ai, bi, aiprime, biprime) # Not compatible with Julia 1.0 | ||
| return (ai=ai, bi=bi, aiprime=aiprime, biprime=biprime) # Compatible with Julia 1.0 |
There was a problem hiding this comment.
given that users of this function only use 1 set of these, the interface seems slightly awkward.
There was a problem hiding this comment.
To obtain the zeros of airyai by writing airy_zeros().ai doesn't seem too onerous to me, and since it's a tuple there aren't any allocations involved in the call. That said, I'm open to suggestions for a more elegant interface.
|
There is some trailing whitespace in src/FunctionZeros.jl that should be removed. |
| for alphak in (alpha1, alpha2, alpha3, alpha4, alpha5) | ||
| xpk *= x | ||
| nextterm = alphak * xpk | ||
| abs(nextterm) > abs(lastterm) && break # Asymptotic series starting to diverge |
There was a problem hiding this comment.
is this early break actually faster? this loop has a maximum of 5 iters
There was a problem hiding this comment.
The early break isn't intended to reduce execution time but rather the error in the partial sum. Since it's an asymptotic series, the "truncation error" can start to grow with additional terms, unlike a convergent series.
* Remove trailing white spaces
|
@jlapeyre Sorry about the white space--don't know why it keeps crawling in there, but I think it's now gone and I've configured VS Code to eliminate it from now on. |
|
Any other changes you'd like to see? |
|
lgtm |
|
@jlapeyre If there are no other changes you desire, would you consider merging this PR? TIA! |
|
@oscardssmith Is this good to merge from your point of view? |
|
If so, I can merge this and make a new release. |
|
sgtm |
|
Thanks, @DilumAluthge and @oscardssmith! |


Add methods to
bessel_zero_asymptoticandbessel_deriv_zero_asymptoticthat promotenufromIntegerto float. Fixes Issue #27