Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exponential integral function #236

Merged
merged 19 commits into from
Oct 19, 2020
Merged

Conversation

augustt198
Copy link
Contributor

@augustt198 augustt198 commented Aug 3, 2020

This PR adds the exponential integral En(ν, z) for both complex ν and z. The special case ν = 1 is optimized in function E₁(z), which is based on Steven Johnson's code in #19.

Not all test cases are passing yet, so this is still a draft.

TODO:

  • E₁(z)
    • Remove Polynomials.jl dependency
    • Tune Taylor series crossover
    • Use SIMD optimized evalpoly
  • En(ν, z)
    • Consistently handle large ν: avoid multiplying complex numbers with Inf
    • Find better crossover boundary between Taylor series & continued fractions
    • Add more test cases with integer arguments: worried about hitting poles in gamma function
    • Better criteria for choosing to use the continued fraction with gamma: En(41 - 23im, 30 + 404im) fails
    • Type stability
  • Documentation

@stevengj
Copy link
Member

stevengj commented Aug 3, 2020

(@augustt198 has been working on this with me as part of UROP project at MIT.)

src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
@stevengj
Copy link
Member

stevengj commented Aug 3, 2020

You did a bunch of benchmarks against external codes — it would be good to post a few of those here.

@stevengj
Copy link
Member

stevengj commented Aug 3, 2020

Can we now provide complex support for gamma_inc? How does this code compare to gamma_inc in the cases where they agree?

src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated Show resolved Hide resolved
src/expint.jl Outdated
x < 4.0 && return @E₁_cf64(x, 16, [5.114292670961982, -1.2789140459431323, 0.22066200334871455, -0.015067049382830766])
x < 6.1 && return @E₁_cf64(x, 14, [4.194988480897909, -0.7263593325667503, 0.08956574399359891, -0.00434973529065973])
x < 8.15 && return @E₁_cf64(x, 9, [3.0362016309948228, -0.33793806630590445, 0.029410409377178114, -0.0010060498260648586])
x < 25.0 && return @E₁_cf64(x, 8, [2.5382065303376895, -0.18352177433259526, 0.011141562002742184, -0.0002634921890930066])
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

ApproxFun claims that a degree-16 polynomial gives machine precision over the 2.15..3.0 interval, for example, and presumably a minimax function could do even better.

Copy link
Member

Choose a reason for hiding this comment

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

Note that you will want to pass a weighting function of 1/E₁ to ratfn_minimax so that it minimizes the maximum relative error.

src/expint.jl Outdated Show resolved Hide resolved
@stevengj
Copy link
Member

stevengj commented Oct 5, 2020

Tests are currently failing, for example:

  Expression: expint(1, -5 + 0.01im) ⩭ -40.18408805785205 - 2.8447696994032254im
   Evaluated: -40.18408805608827 - 2.8447696977664467im ⩭ -40.18408805785205 - 2.8447696994032254im

for example

Test Summary:          | Pass  Fail  Error  Total
expint                 |  925     1      5    931
  exponential integral |  925     1      5    931
    E1 real            |  309                 309
    E1 complex         |  488                 488
    En                 |  128     1      5    134

@stevengj
Copy link
Member

stevengj commented Oct 19, 2020

test failure:

E1 complex: Test Failed at /Users/travis/build/JuliaMath/SpecialFunctions.jl/test/expint.jl:31
  Expression: expint(x) ≅ y
   Evaluated: 5.733317091369105e-42 + 4.0193199136184414e-39im ≅ 5.7333170913660523e-42 + 4.019319913618439e-39im

The relative error in the real part is 5.3e-13, which is slightly above your tolerance but should be okay — apparently due to a slight compiler difference on another platform?

@test_throws ArgumentError expint(-50+100im, 5+5im) ⩭ 0.00004495913300988524775299480665674170202100859018442234 - 0.00003791061255142431660134050245626121520797056806394134im
@test_throws ArgumentError expint(0.0001-100im, 5+5im) ⩭ -0.0000670979311229384710017493655410977414867979779532195 + 0.0000229212453762433221017163627753752485911057259666081im
@test_throws ArgumentError expint(-100-100im, 5+5im) ⩭ -6.08640887739723453551143736571517308449904372104665e86 - 1.89339595225376542869023397967131390592967463726985e87im
@test_throws ArgumentError expint(-67.7427839203913 - 53.20793098548715im, -18.33277989291684 + 5.734337337627761im) ⩭ -8.98320096334454197835241406421715692910936300308912e64 + 5.24063785033491832811625264321940307636652348236306e64im
Copy link
Member

Choose a reason for hiding this comment

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

real ν > 50 are supported, so we should test some of those cases.

@stevengj
Copy link
Member

Regarding the failing test, since it seems to just be slightly worse roundoff error in the real part on one machine (and the overall error in z is quite small), I don't think it's worth getting to the bottom of what is probably a compiler quirk — just test it with the lower 5e-12 tolerance from the other tests.

@stevengj stevengj changed the title Exponential integral function: draft Exponential integral function Oct 19, 2020
@stevengj
Copy link
Member

stevengj commented Oct 19, 2020

Note: you can implement the incomplete gamma function in terms of this. To get the equivalent of gamma_inc, do:

gamma_inc2(a,x) = let q = expint(1-a,x) * x^a / gamma(a); 1-q, q; end

(However, this might give an inaccurate first value, the lower incomplete gamma function ratio, if q is close to 1.)

It actually seems to be significantly faster than our current gamma_inc function, however, and has the additional advantage of supporting complex arguments!

@eschnett
Copy link

Do you want to make a new minor release for expint?

@stevengj
Copy link
Member

Once #263 is fixed, which should happen next week.

@stevengj
Copy link
Member

Tagged. Since the api has been stable for a while, and Julia’s package system strongly favors >= 1.0 versions for compatibility tracking, I tagged it as 1.0

@oscardssmith
Copy link
Member

Should there be documentation for this?

@stevengj
Copy link
Member

It's in the "dev" docs; I'm not sure why it hasn't appeared in the "stable" docs yet?

@giordano
Copy link
Member

For some reasons I don't currently understand, documentation is built only on pushes to master, but not creation of tags. At a quick glance, the setup looks correct to me

@giordano
Copy link
Member

giordano commented Feb 16, 2021

Oh, I see now: the setup was fixed with #287, which was merged on December 21st, but the latest release is v1.2.1, from December 16th. So the next release should hopefully have the documentation built regularly. See also #286

@stevengj
Copy link
Member

Should be fixed by JuliaRegistries/General#30169

@giordano
Copy link
Member

Yes, https://juliamath.github.io/SpecialFunctions.jl/stable/ now points to v1.3.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants