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

Limit number of Newton iterations in beta_inc_inv #396

Closed
wants to merge 1 commit into from

Conversation

andreasnoack
Copy link
Member

and allow much smaller starting values.

I checked with the original Fortran version and it also hangs on the test problem. However, I think for different reasons since their tolerance is much higher than ours and the problem here is that we can't get below the 2.2250738585071875e-308 tolerance. I'm a little skeptical that such a small tolerance is generally workable but the Fortran source comments that

Define accuracy and initialise.
SAE below is the most negative decimal exponent which does not
cause an underflow; a value of -308 or thereabouts will often be
OK in double precision.

I put the limit at 30 which is completely arbitrary but with a good starting value, I believe it should be fine. I decided to raise a debug warning when the function hits the iteration max. The clamping away from zero and one in

if x < 0.0001
x = 0.0001
end
if x > .9999
x = .9999
end
ruined small initial guesses, though, and it seems wrong to me to clamp away from zero with the same distance as the distance from one given the much higher density of numbers around zero. Without the change to the lower bound, the test case wouldn't reach a reasonable value within the 30 iterations limit.

@codecov
Copy link

codecov bot commented Mar 17, 2022

Codecov Report

Merging #396 (37c0c62) into master (ce58a13) will decrease coverage by 54.68%.
The diff coverage is 100.00%.

@@             Coverage Diff             @@
##           master     #396       +/-   ##
===========================================
- Coverage   91.99%   37.30%   -54.69%     
===========================================
  Files          12       12               
  Lines        2809     2761       -48     
===========================================
- Hits         2584     1030     -1554     
- Misses        225     1731     +1506     
Flag Coverage Δ
unittests 37.30% <100.00%> (-54.69%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/beta_inc.jl 91.47% <100.00%> (-1.14%) ⬇️
src/ellip.jl 0.00% <0.00%> (-100.00%) ⬇️
src/chainrules.jl 0.00% <0.00%> (-100.00%) ⬇️
src/SpecialFunctions.jl 0.00% <0.00%> (-100.00%) ⬇️
src/erf.jl 2.59% <0.00%> (-97.41%) ⬇️
src/expint.jl 0.00% <0.00%> (-95.20%) ⬇️
src/betanc.jl 0.00% <0.00%> (-90.20%) ⬇️
src/gamma.jl 14.52% <0.00%> (-78.50%) ⬇️
src/gamma_inc.jl 21.60% <0.00%> (-68.42%) ⬇️
src/sincosint.jl 0.00% <0.00%> (-65.46%) ⬇️
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ce58a13...37c0c62. Read the comment docs.

Copy link
Member

@devmotion devmotion left a comment

Choose a reason for hiding this comment

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

It seems the changes cause test failures.

@@ -968,8 +971,8 @@ function _beta_inc_inv(a::Float64, b::Float64, p::Float64, q::Float64=1-p)
sq = 1.0
prev = 1.0

if x < 0.0001
x = 0.0001
if x < 1e-200
Copy link
Member

Choose a reason for hiding this comment

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

Is there any specific reason for this choice?

Copy link
Member

Choose a reason for hiding this comment

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

Implementation-wise, it seems the section here could be simplified to

    x = clamp(x, 1e-200, 0.9999)

@@ -1026,7 +1029,7 @@ function _beta_inc_inv(a::Float64, b::Float64, p::Float64, q::Float64=1-p)
end

#check if current estimate is acceptable

prev, acu, p_approx, x, tx
Copy link
Member

Choose a reason for hiding this comment

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

I assume this was for debugging?

Suggested change
prev, acu, p_approx, x, tx

@@ -1001,7 +1004,7 @@ function _beta_inc_inv(a::Float64, b::Float64, p::Float64, q::Float64=1-p)
acu = exp10(iex)

#iterate
while true
for i in 1:maxiter
Copy link
Member

Choose a reason for hiding this comment

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

Maybe

Suggested change
for i in 1:maxiter
for _ in 1:maxiter

since we don't use i?

@@ -1039,6 +1042,9 @@ function _beta_inc_inv(a::Float64, b::Float64, p::Float64, q::Float64=1-p)
x = tx
p_approx_prev = p_approx
end

@debug "Newton iterations didn't converge in $maxiter iterations. The result might have reduced precision."
Copy link
Contributor

Choose a reason for hiding this comment

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

This probably deserves a higher logging level?

Suggested change
@debug "Newton iterations didn't converge in $maxiter iterations. The result might have reduced precision."
@warn "Newton iterations didn't converge in $maxiter iterations. The result might have reduced precision."

Copy link
Member Author

Choose a reason for hiding this comment

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

I deliberately chose @debug over @warn to avoid that we raise warnings in normal usage. These functions sometimes lose precision in corner cases and it's not something we generally warn about. Eventually, we should have a better and more granular way of providing this information. E.g. via error codes and that's why I added the @debug statement.

@andreasnoack
Copy link
Member Author

The error here is because one of the existing test cases need a lot of iterations to converge. The starting values are really bad. I've read the two papers behind this implementation and I'm not trying to figure out if the starting values can be improved in the case that currently fails.

devmotion added a commit that referenced this pull request May 17, 2022
* Limit number of Newton iterations in beta_inc_inv and allow much
smaller starting values.

* Adjust tolerance instead of number of iterations

Co-authored-by: Andreas Noack <andreas@noack.dk>
@devmotion
Copy link
Member

The issue was fixed by #399.

@devmotion devmotion closed this May 17, 2022
devmotion added a commit that referenced this pull request May 17, 2022
* Limit number of Newton iterations in beta_inc_inv and allow much
smaller starting values.

* Adjust tolerance instead of number of iterations

Co-authored-by: Andreas Noack <andreas@noack.dk>
devmotion added a commit that referenced this pull request May 24, 2022
* Fix hangs in `beta_inc_inv` (alternative/extension of #396) (#399)

* Limit number of Newton iterations in beta_inc_inv and allow much
smaller starting values.

* Adjust tolerance instead of number of iterations

Co-authored-by: Andreas Noack <andreas@noack.dk>

* Release 1.8.5

Co-authored-by: Andreas Noack <andreas@noack.dk>
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

3 participants