Skip to content

Add logit, logistic_sigmoid, and use in logistic dist to support promotion policies #1297

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

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from

Conversation

mborland
Copy link
Member

Closes: #1294
Closes: #1296

@jzmaddock
Copy link
Collaborator

Thanks for this Matt!

Copy link

codecov bot commented Aug 12, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.07%. Comparing base (4d7d6e1) to head (79ab23f).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1297      +/-   ##
===========================================
+ Coverage    91.51%   95.07%   +3.55%     
===========================================
  Files          558      796     +238     
  Lines        53881    67011   +13130     
===========================================
+ Hits         49311    63708   +14397     
+ Misses        4570     3303    -1267     
Files with missing lines Coverage Δ
include/boost/math/distributions/logistic.hpp 80.25% <100.00%> (-0.96%) ⬇️
.../boost/math/special_functions/logistic_sigmoid.hpp 100.00% <100.00%> (ø)
include/boost/math/special_functions/logit.hpp 100.00% <100.00%> (ø)
test/math_unit_test.hpp 22.95% <100.00%> (ø)
test/test_logistic_sigmoid.cpp 100.00% <100.00%> (ø)
test/test_logit.cpp 100.00% <100.00%> (ø)

... and 335 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@WarrenWeckesser WarrenWeckesser left a comment

Choose a reason for hiding this comment

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

That was fast!

I have a question below about using the promoted type with the location/scale calculations that occur outside of the calls of logit or logistic_sigmoid.

Also a couple minor nitpicks involving minus signs.

if(power < -tools::log_max_value<RealType>())
return 1;
return 1 / (1 + exp(power));
RealType power = -(location - x) / scale;
Copy link
Contributor

Choose a reason for hiding this comment

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

Here and below: shouldn't this calculation also use the promoted type? E.g. suppose location is 0, scale is 3, and x is 1. If RealType is double precision, then power is 0.3333333333333333, which becomes 0.33333333333333331483 when promoted to extended precision. If the translation and scaling uses the promoted type, then power should be 0.33333333333333333334, and that is the value that I would expect to be passed to logistic_sigmoid.

Copy link
Member Author

Choose a reason for hiding this comment

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

Having power as a promoted type makes sense. I then added the ability to disable further promotion to logistic_sigmoid. I was thinking about this case with the policy from your original issue[1]: RealType is float which means that power would be promoted to double. Without further disabling promotion logistic_sigmoid would compute internally using long double rather than staying at the already promoted type of double.

[1]

typedef policy<
    promote_float<true>,
    promote_double<true>
> with_promotion;

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I was wondering how disabling a second promotion would work out.

Adding that boolean template parameter to the function seems a bit awkward. Now logistic_sigmoid has a regular Policy parameter, and a parameter to disable promotion in that Policy. Most users of logistic_sigmoid would never need it--they could just use an appropriately defined Policy. Also, I think this boolean parameter would have to be added to any other special functions that get called from within distribution functions (assuming an audit of the other distributions finds more cases where promotion isn't fully implemented).

Instead, in the cdf function, could policies::normalise be used to define a new policy from the existing one, with promotion disabled? This appears to be the suggestion given at the bottom of https://www.boost.org/doc/libs/1_87_0/libs/math/doc/html/math_toolkit/pol_tutorial/policy_tut_defaults.html.

So something like

 normalise<Policy, promote_float<false>, promote_double<false>>::type

would be the policy used when, say, cdf calls logistic_sigmoid.

This worked for a trivial example that I created with lambert_w0 (just to test the idea), but I haven't tried updating this PR with such a change, so I don't know if there are obstacles to making it work.

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.

Proposed update for the quantile function of the logistic distribution. Double promotion for the logistic quantile doesn't work?
3 participants