Skip to content

logstatsexp#77

Closed
cossio wants to merge 9 commits into
JuliaStats:masterfrom
cossio:stats
Closed

logstatsexp#77
cossio wants to merge 9 commits into
JuliaStats:masterfrom
cossio:stats

Conversation

@cossio

@cossio cossio commented Nov 11, 2023

Copy link
Copy Markdown
Contributor

Adds the functions logmeanexp, logvarexp, logstdexp

@cossio

cossio commented Nov 11, 2023

Copy link
Copy Markdown
Contributor Author

These functions are usually useful for me, thought it'd be nice to have them here.

Not sure why CI is failing on Julia 1.0 ?

Comment thread src/logstatsexp.jl Outdated
Comment thread src/logstatsexp.jl Outdated
Comment thread src/logstatsexp.jl
function logmeanexp(A::AbstractArray; dims=:)
R = logsumexp(A; dims)
N = length(A) ÷ length(R)
return R .- log(N)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will cause undesired promotions and allocations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think it's better now.

@devmotion devmotion Nov 11, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It seems you adressed my comment about promotions but not the allocations.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@devmotion you might argue that unless there's a way to modify logsumexp to directly take log(N) into account, an in-place operation might create issues with AD systems which do not support it?

Comment thread src/logstatsexp.jl Outdated
Comment thread src/logstatsexp.jl
R = logsumexp(2logsubexp.(A, logmean); dims)
N = length(A) ÷ length(R)
if corrected
return R .- log(N - 1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Again this causes undesired promotions and allocations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I think it's better now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The unnecessary allocations are still present.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Then I'm not sure what you are referring to?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

R .- log(N - 1)

creates a new array. But if R is e.g. of type Array this causes unnecessary allocations.

Comment thread test/logstatsexp.jl Outdated
@longemen3000

longemen3000 commented Nov 11, 2023

Copy link
Copy Markdown
Contributor

I don't have an strong opinion on this, but Is it possible to implement this as an extension? This package is a really low level one, and adding a new dependency could have effects on downstream packages?
The same thing applies to LinearAlgebra, (but they should be it's own issue)

@cossio

cossio commented Nov 11, 2023

Copy link
Copy Markdown
Contributor Author

@longemen3000 The PR is not introducing any dependencies.

@longemen3000

Copy link
Copy Markdown
Contributor

Statistics, while a Stdlib, it is a new dependency

Comment thread src/logstatsexp.jl Outdated
@longemen3000

longemen3000 commented Nov 11, 2023

Copy link
Copy Markdown
Contributor

Ohhh, nvm, my error, in that case, no comment at all

@cossio

cossio commented Nov 11, 2023

Copy link
Copy Markdown
Contributor Author

@longemen3000 Yes but Statistics is only used in tests

@cossio

cossio commented Nov 11, 2023

Copy link
Copy Markdown
Contributor Author

CI passing now.

@devmotion I agree the implementation is not optimal but I don't have time to tune it now. Could we merge as it is now?

@ParadaCarleton

Copy link
Copy Markdown

I think we can merge now and work on optimization later.

Honestly, it's just a huge pain trying to optimize for allocations without having Transducers.jl, laziness, or good functional primitives in Julia.

@devmotion

devmotion commented Nov 11, 2023

Copy link
Copy Markdown
Member

@ParadaCarleton as far as I know you've never contributed to this package, so I really think that you should let the maintainers of this package decide when a PR is ready and can be merged. In my opinion, being a member of JuliaStats doesn't mean that you are able and should merge PRs in repos that you haven't contributed to and/or are not familiar with. For instance, there are many JuliaStats packages where I don't think it's appropriate for me to merge PRs.

@devmotion

Copy link
Copy Markdown
Member

Clearly, we should not over-optimize this PR. But at the same time we should hold off merging PRs if reviewer comments that can be addressed without too much effort are not resolved. For instance, I think currently the following things are missing in this PR:

  • Definitions for non-AbstractArray inputs (it seems the same algorithm could be applied?)
  • Avoiding allocating R .- log(N) etc. when R is an Array and broadcasting when R is a scalar
  • Tests with non-Float64 inputs (these would have uncovered the promotion issues)

@tpapp

tpapp commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

I am closing this because of no activity. If there is interest, please bump here and I will reopen. That said, a fresh start would be preferred, addressing all the concerns here.

@cossio

cossio commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@tpapp @devmotion Retrying at #120

cossio added a commit to cossio/LogExpFunctions.jl that referenced this pull request Jun 4, 2026
…ogstdexp

Rework the log-mean/var/std-exp reductions around a single primitive
(`logsumexp(X)`, `logsumexp(2X)`, count), addressing review feedback in
JuliaStats#120 and JuliaStats#77:

- Use a single pass over general iterators (works for one-shot iterators
  such as `Iterators.Stateful`); take the count from `length` for arrays
  instead of accumulating it, as suggested by @tpapp.
- Drop the explicit empty/`NaN` special-casing: for a single element the
  arithmetic already yields `NaN` (`-Inf - log(0)`), per @tpapp's note.
- Remove the `logmean` keyword and the parallel array/iterator variance
  helpers; everything now flows through `_logvar`/`_logmoments`.
- No promotion of `Float32` inputs; full reductions allocate nothing.

Add `logmeanexp_and_logvarexp` and `logmeanexp_and_logstdexp` (the
`mean_and_var` / `mean_and_std` analogues, also suggested by @tpapp),
computing both statistics in a single pass.

Tests: extend coverage with the new functions, allocation checks
(zero allocations for full reductions over arrays/iterators), and
type-stability/`@inferred` checks across `Float32`/`Float64`, `dims`,
and `corrected`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

6 participants