forked from JuliaStats/LogExpFunctions.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
Simplify logstatsexp reductions: length-aware iterators and direct normalization
#1
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
Copilot
wants to merge
40
commits into
master
Choose a base branch
from
copilot/retry-pr-77
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
5b96b87
Add logmeanexp/logvarexp/logstdexp implementations
Copilot aa991ca
Fix logstats iterator implementation and tests
Copilot 3930a78
Add PR77-focused logstatsexp tests
Copilot 0431c84
Fix PR review issues in logstatsexp
Copilot 6c42836
Fix unresolved review comments: remove dead _count_elements, update d…
Copilot 7f14412
Use explicit multiplication in logstatsexp
Copilot 28fc64e
fix iterator real-input validation for log variance
Copilot 7a886c1
refactor iterator counting and simplify normalization logic
Copilot e760614
Simplify logstatsexp; add logmeanexp_and_logvarexp / logmeanexp_and_l…
cossio 3842a7e
Use the numerically stable centered variance; fix min-Julia CI
cossio 6789ee6
Use scalar `/ 2` instead of broadcast `./ 2` for std
cossio 8c421b5
Potential fix for pull request finding
cossio 73f2e55
Potential fix for pull request finding
cossio 9fa4627
Fuse dims variance into logsumexp; repair empty-array testset
cossio dadf0d9
Fix dims-reduction correctness bugs found in review; drop lazy wrapper
cossio 695b2ef
Simplify: dedup the one-pass reduction loops
cossio 23f5dc4
Make logmeanexp single-pass; fix single-use HasLength iterators
cossio 8fafe93
Apply suggestion from @devmotion
cossio c9439aa
Apply suggestion from @devmotion
cossio 1be77c1
Apply suggestion from @devmotion
cossio 691e34e
Clean up logstatsexp per review feedback
cossio 09a8da1
Add in-place logmeanexp!/logvarexp!; dims reductions allocate only th…
cossio 5601c23
Use keyword-argument punning in logstatsexp tests
cossio 9669d64
Remove combined logmeanexp_and_* functions
cossio 8de5fea
simplifications
cossio 1fff6ba
comment
cossio 9983e1f
simplify more
cossio 44ddd37
rm AbstractRange redundant
cossio ef4756d
_finish_logvar
cossio 172d5b8
chainrules
cossio f1f82da
no iterator support in logvarexp
cossio 0a900f0
logstdexp! tests
cossio 850df33
nits
cossio b245d7d
simplify pullback
cossio 0ce6af4
rm _logsumexp_count
cossio e6cc62a
Simplify oftype usage and add return-type tests
cossio 82d59b1
comments
cossio 69f455b
Shorten test comments
cossio 310aecb
Stop tracking .claude worktrees
cossio 899b08f
Remove .claude from .gitignore
cossio File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| # Numerically stable `log`-of-statistics-of-`exp` reductions: | ||
| # logmeanexp, logvarexp, logstdexp. | ||
|
|
||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Compute `log(mean(exp, X))` in a numerically stable way. | ||
|
|
||
| `X` should be an iterator of numbers. For an array, `dims` selects the dimensions to reduce | ||
| over, returning `log.(mean(exp.(X); dims))`. | ||
|
|
||
| See also [`logmeanexp!`](@ref). | ||
| """ | ||
| function logmeanexp(X) | ||
| next = iterate(X) | ||
| isnothing(next) && throw(ArgumentError("reducing over an empty collection is not allowed")) | ||
| x, state = next | ||
| acc = x | ||
| count = 1 | ||
| while true | ||
| next = iterate(X, state) | ||
| isnothing(next) && break | ||
| x, state = next | ||
| acc = _logsumexp_onepass_op(acc, x) | ||
| count += 1 | ||
| end | ||
| lse = _logsumexp_onepass_result(acc) | ||
| return oftype(lse, lse - log(count)) | ||
| end | ||
| logmeanexp(X::AbstractArray{<:Number}; dims=:) = _logmeanexp(X, dims) | ||
| function _logmeanexp(X::AbstractArray{<:Number}, ::Colon) | ||
| out = logsumexp(X) | ||
| return oftype(out, out - log(length(X))) | ||
| end | ||
| function _logmeanexp(X::AbstractArray{<:Number}, dims) | ||
| out = similar(X, float(eltype(X)), Base.reduced_indices(axes(X), dims)) | ||
| return logmeanexp!(out, X) | ||
| end | ||
|
|
||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Compute [`logmeanexp`](@ref) of `X` over the singleton dimensions of `out`, and write the | ||
| result to `out`. | ||
| """ | ||
| function logmeanexp!(out::AbstractArray, X::AbstractArray{<:Number}) | ||
| logsumexp!(out, X) | ||
| return out .-= log(length(X) / length(out)) | ||
| end | ||
|
|
||
|
|
||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Compute `log(var(exp.(X); corrected))` in a numerically stable way. | ||
|
|
||
| `X` should be an array of real numbers; `dims` selects the dimensions to reduce over, | ||
| returning `log.(var(exp.(X); dims, corrected))`. A precomputed `logmeanexp(X; dims)` can be | ||
| passed as `logmean` to avoid recomputing it. | ||
|
|
||
| See also [`logvarexp!`](@ref). | ||
| """ | ||
| logvarexp(X::AbstractArray{<:Real}; dims=:, corrected::Bool=true, logmean=logmeanexp(X; dims)) = _logvarexp(X, dims, corrected, logmean) | ||
| function _logvarexp(X::AbstractArray{<:Real}, ::Colon, corrected::Bool, logmean) | ||
| out = logsumexp(2 .* logsubexp.(X, logmean)) | ||
| return oftype(out, out - log(max(0, length(X) - corrected))) | ||
| end | ||
| function _logvarexp(X::AbstractArray{<:Real}, dims, corrected::Bool, logmean) | ||
| out = logsumexp(2 .* logsubexp.(X, logmean); dims) | ||
| return out .-= log(max(0, length(X) / length(out) - corrected)) | ||
| end | ||
|
|
||
|
|
||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Compute [`logvarexp`](@ref) of `X` over the singleton dimensions of `out`, and write the | ||
| result to `out`. | ||
| """ | ||
| function logvarexp!(out::AbstractArray{<:Real}, X::AbstractArray{<:Real}; corrected::Bool=true) | ||
| logmeanexp!(out, X) | ||
| logsumexp!(out, 2 .* logsubexp.(X, out)) | ||
| return out .-= log(max(0, length(X) / length(out) - corrected)) | ||
| end | ||
|
|
||
|
|
||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Compute `log(std(exp.(X); dims, corrected))` in a numerically stable way. | ||
|
|
||
| Keyword arguments are as in [`logvarexp`](@ref). | ||
| """ | ||
| logstdexp(X::AbstractArray{<:Real}; dims=:, corrected::Bool=true, logmean=logmeanexp(X; dims)) = logvarexp(X; dims, corrected, logmean) / 2 | ||
|
|
||
|
|
||
| """ | ||
| $(SIGNATURES) | ||
|
|
||
| Compute [`logstdexp`](@ref) of `X` over the singleton dimensions of `out`, and write the | ||
| result to `out`. | ||
| """ | ||
| function logstdexp!(out::AbstractArray{<:Real}, X::AbstractArray{<:Real}; corrected::Bool=true) | ||
| logvarexp!(out, X; corrected) | ||
| return out ./= 2 | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.