Skip to content

fix: correct entropy formulas for Pareto, Geometric, StudentsT, and Dirichlet#383

Open
gaoflow wants to merge 1 commit into
statrs-dev:masterfrom
gaoflow:fix-entropy-formulas
Open

fix: correct entropy formulas for Pareto, Geometric, StudentsT, and Dirichlet#383
gaoflow wants to merge 1 commit into
statrs-dev:masterfrom
gaoflow:fix-entropy-formulas

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 16, 2026

Copy link
Copy Markdown

Four entropy() implementations return wrong values. Against the closed forms:

Pareto(x_m, α) — differential entropy is ln(x_m/α) + 1/α + 1. The implementation (and its doc
comment) compute ln(α/x_m) - 1/α - 1, the exact negation of every term.

Geometric(p) — the formula shape is right but uses .log(2.0), so the result is in bits. Every
other entropy in the crate is in nats.

StudentsT(μ, σ, ν) — for Y = μ + σX, H(Y) = H(X) + ln σ. The code applies
shift = -scale.ln(); the derivation comment above it states the same relation with the sign
flipped. Values are correct at σ = 1 and wrong for every other scale.

Dirichlet(α) — the method's doc comment has the correct formula
(ln B(α) + (α₀ - K)ψ(α₀) - Σ(αᵢ-1)ψ(αᵢ)), but the implementation folds ln Γ(αᵢ) into the
accumulator that gets subtracted, so Σ ln Γ(αᵢ) enters with the wrong sign.

To find the extent I ran all 27 entropy() implementations in the crate against scipy 1.17.1
(63 parameter sets). These four are the only formula errors:

case statrs (master) scipy / closed form
Pareto::new(1.0, 3.0) -0.234721044665 0.234721044665
Geometric::new(0.5) 2.0 1.386294361120 (= 2 ln 2)
StudentsT::new(0.0, 3.0, 5.0) 0.528890383746 2.726114961083
Dirichlet::new(vec![0.1, 0.3, 0.5, 0.8]) -17.464690810941 -9.318820275187

Everything else agrees to 1e-9 relative or better. (The one remaining deviation is Poisson, whose
entropy is a large-λ asymptotic series that drifts for small λ — an approximation-accuracy question
left out of this PR.)

The existing test_entropy cases for Pareto, Geometric, and Dirichlet asserted the buggy outputs —
Pareto's five expected values are each the negation of the correct one, and Dirichlet's expected
values match the sign-flipped formula to within 1e-30 — i.e. they were generated from the
implementation rather than derived independently. This PR corrects those assertions to
closed-form values cross-checked against scipy, adds more parameter points, and adds an entropy
test for StudentsT, which had none (including location-invariance and a scale < 1 point).

…irichlet

- Pareto: formula was the exact negation of ln(x_m/a) + 1/a + 1
- Geometric: used log base 2, returning bits instead of nats
- StudentsT: scale shifted entropy by -ln(scale) instead of +ln(scale)
- Dirichlet: sum of ln_gamma(alpha_i) entered with the wrong sign

Existing test assertions for Pareto, Geometric, and Dirichlet encoded the
buggy outputs; corrected to closed-form values cross-checked against scipy
and extended with more parameter points. Added an entropy test for
StudentsT, which had none.
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.

1 participant