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

Improve type stability for truncated normal moments #1717

Merged
merged 2 commits into from
May 10, 2023
Merged

Improve type stability for truncated normal moments #1717

merged 2 commits into from
May 10, 2023

Conversation

ararslan
Copy link
Member

@ararslan ararslan commented May 6, 2023

The internal functions used for computing the mean and variance of the truncated normal distribution were implemented using literals like √2, which are always Float64. However, some branches of the functions based the return type off of the types of the arguments, which needn't be Float64. This led to some instability that can be seen via @code_warntype. For example, the inferred result of _tnmom1 for Float32 inputs was Union{Float32,Float64}.

We can instead use the irrational constants defined for square roots of pi and 2 and ratios thereof in order to avoid promoting to Float64 unnecessarily. This makes the return type concretely inferrable and provides a small performance improvement, about 12% better (-7ns) for mean and 14% better (-20ns) for var on my machine as compared to current master.

The internal functions used for computing the mean and variance of the
truncated normal distribution were implemented using literals like `√2`,
which are always `Float64`. However, some branches of the functions
based the return type off of the types of the arguments, which needn't
be `Float64`. This led to some instability that can be seen via
`@code_warntype`. For example, the inferred result of `_tnmom1` for
`Float32` inputs was `Union{Float32,Float64}`.

We can instead use the irrational constants defined for square roots of
pi and 2 and ratios thereof in order to avoid promoting to `Float64`
unnecessarily. This makes the return type concretely inferrable and
provides a small performance improvement, about 7 ns for `mean` and 20
ns for `var` on my machine as compared to current master.
@codecov-commenter
Copy link

codecov-commenter commented May 6, 2023

Codecov Report

Patch coverage: 84.61% and no project coverage change.

Comparison is base (d460846) 85.82% compared to head (00854d3) 85.83%.

❗ Current head 00854d3 differs from pull request most recent head c42b796. Consider uploading reports for the commit c42b796 to get more accurate results

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1717   +/-   ##
=======================================
  Coverage   85.82%   85.83%           
=======================================
  Files         137      137           
  Lines        8318     8322    +4     
=======================================
+ Hits         7139     7143    +4     
  Misses       1179     1179           
Impacted Files Coverage Δ
src/truncated/normal.jl 85.82% <84.61%> (+0.43%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

src/truncated/normal.jl Outdated Show resolved Hide resolved
src/truncated/normal.jl Outdated Show resolved Hide resolved
src/truncated/normal.jl Outdated Show resolved Hide resolved
src/truncated/normal.jl Outdated Show resolved Hide resolved
src/truncated/normal.jl Outdated Show resolved Hide resolved
Co-authored-by: David Widmann <devmotion@users.noreply.github.com>
end
Δ = (b - a) * middle(a, b)
Δ = (b - a) * mid
a′ = a * invsqrt2
Copy link
Member Author

Choose a reason for hiding this comment

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

@devmotion, I'm curious if you have any thoughts on this approach vs. a / sqrt2. They seem to be extremely close but not exactly identical (but close enough to not affect the tests). Similar situation for the division of things by sqrthalfπ vs. defining a separate irrational for sqrt(2/π) and multiplying.

Copy link
Member

Choose a reason for hiding this comment

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

Hm no, to me both approaches seem fine. I guess if an irrational of the inverse exists, multiplication might be faster and therefore preferable.

Copy link
Member Author

Choose a reason for hiding this comment

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

That was my thought as well, just wasn't sure whether there was something I might be missing in terms of potential loss of precision or things like that

@ararslan ararslan merged commit fa8c30d into master May 10, 2023
@ararslan ararslan deleted the aa/tn branch May 10, 2023 15:34
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