Skip to content

Add argument confidence_interval_root_find indicating root finding method#265

Merged
dachengx merged 6 commits intomainfrom
confidence_interval_root_find
Feb 28, 2026
Merged

Add argument confidence_interval_root_find indicating root finding method#265
dachengx merged 6 commits intomainfrom
confidence_interval_root_find

Conversation

@dachengx
Copy link
Collaborator

@dachengx dachengx commented Feb 24, 2026

When calculating CL, if confidence_interval_root_find is brentq, use scipy.optimize.brentq; if extremal, look for the left or right-most root.

The left- right- most root finding is performed in utils.extremal_root. This function accepts almost the same arguments as scipy.optimize.brentq.

@coveralls
Copy link

coveralls commented Feb 24, 2026

Pull Request Test Coverage Report for Build 22446669536

Details

  • 40 of 45 (88.89%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.2%) to 76.425%

Changes Missing Coverage Covered Lines Changed/Added Lines %
alea/utils.py 26 31 83.87%
Totals Coverage Status
Change from base Build 20990013760: 0.2%
Covered Lines: 1757
Relevant Lines: 2299

💛 - Coveralls

@dachengx dachengx requested a review from hammannr February 24, 2026 15:53
@hammannr
Copy link
Collaborator

On a first quick look this looks very nice! Could you think of a quick unites to make sure it stays that nice? 😄

@dachengx
Copy link
Collaborator Author

Thanks @hammannr . I have added a simple test of the new method

Copy link
Collaborator

@hammannr hammannr left a comment

Choose a reason for hiding this comment

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

I didn't run it yet, but just had a look at the code. Looks mostly good, and I will try running it asap. In the meantime, I left a few comments on things I noticed so far.

nominal_values={"sigma": 1.0},
parameter_definition=gaussian_model_parameter_definition,
compute_confidence_interval=COMPUTE_CONFIDENCE_INTERVAL,
confidence_interval_root_find="extremal",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not really tests the method, but only if it fails to load it, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here it is tested

if COMPUTE_CONFIDENCE_INTERVAL:

Copy link
Collaborator

Choose a reason for hiding this comment

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

sure but this doesnt' test if the function works properly, does it?

xL,
xR,
which="left",
step=0.01,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we should assert that step is >=0, otherwise this will give unexpected behaviour or infinity loops.

xR,
which="left",
step=0.01,
step_growth=1.0,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same for step growth

Copy link
Collaborator

Choose a reason for hiding this comment

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

This option generally seems a bit unstable to me since it can explode or converge to zero, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it might explode, so I set the default step_growth as 1.0, and the step does not increase.

Comment on lines +609 to +610
confidence_interval_root_find (str, optional (default=None)):
root finding algorithm of confidence interval
Copy link
Collaborator

Choose a reason for hiding this comment

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

For convenience, also state here the two options, please.

alea/utils.py Outdated
Comment on lines +788 to +789
"""Find the left-most or right-most root of f in [xL, xR] using adaptive scanning + brentq
refinement."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add a brief explanation for all the parameters of the function.

@hammannr
Copy link
Collaborator

I played with it a little bit and it' quite easy to find a case in which this produces RuntimeError: No root found in interval:
This works fine:

def function_with_six_roots(x):
    return (x - 1) * (x - 2) * (x - 3) * (x - 4) * (x - 5)* (x - 6)

left_extremal = extremal_root(
    function_with_six_roots,
    xL=-100,
    xR=100,
    which="left")

though this will fail without readjusting the step size:

def function_with_six_small_roots(x):
    return (x - 1e-5) * (x - 2e-5) * (x - 3e-5) * (x - 4e-5) * (x - 5e-5)* (x - 6e-5)

left_extremal = extremal_root(
    function_with_six_small_roots,
    xL=-100,
    xR=100,
    which="left",)

Do you think there is a sensible way to make this a bit more robust?

@dachengx
Copy link
Collaborator Author

I played with it a little bit and it' quite easy to find a case in which this produces RuntimeError: No root found in interval: This works fine:

def function_with_six_roots(x):
    return (x - 1) * (x - 2) * (x - 3) * (x - 4) * (x - 5)* (x - 6)

left_extremal = extremal_root(
    function_with_six_roots,
    xL=-100,
    xR=100,
    which="left")

though this will fail without readjusting the step size:

def function_with_six_small_roots(x):
    return (x - 1e-5) * (x - 2e-5) * (x - 3e-5) * (x - 4e-5) * (x - 5e-5)* (x - 6e-5)

left_extremal = extremal_root(
    function_with_six_small_roots,
    xL=-100,
    xR=100,
    which="left",)

Do you think there is a sensible way to make this a bit more robust?

Maybe 1% of the parameter's boundary?

@hammannr
Copy link
Collaborator

Maybe 1% of the parameter's boundary?
This could work but sometimes people (including myself) use relatively large parameter bounds to ensure the limits are well within. So also there would be some source of stability. This seems like it should be a solved problem, though.

@dachengx
Copy link
Collaborator Author

Maybe 1% of the parameter's boundary?
This could work but sometimes people (including myself) use relatively large parameter bounds to ensure the limits are well within. So also there would be some source of stability. This seems like it should be a solved problem, though.

I hope the analysts will figure out how to scale the parameter of interest to be within meaningful values. I will print a warning when the step is too large/small compared to the poi's boundary.

@dachengx dachengx merged commit 24b5327 into main Feb 28, 2026
9 of 11 checks passed
@dachengx dachengx deleted the confidence_interval_root_find branch February 28, 2026 11:57
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.

3 participants