Skip to content

Add European inverse Pareto distribution (invpareto_eur) - #170

Draft
joethorley wants to merge 10 commits into
devfrom
add-invpareto-eur
Draft

joethorley wants to merge 10 commits into
devfrom
add-invpareto-eur

Conversation

@joethorley

@joethorley joethorley commented Jun 10, 2026 •

Copy link
Copy Markdown
Member

Adds the European form of the inverse Pareto distribution as a new user-selectable distribution invpareto_eur, and makes explicit that the existing invpareto is the North American form, following the convention the distributions article already uses (European = unbounded, as in actuar; North American = bounded, as in extraDistr).

The European version is unbounded above and uses the same shape/scale parameterisation as actuar::dinvpareto(). Both parameters are free MLE parameters with an interior optimum, so unlike the bounded North American form it is registered with valid = TRUE and can be model averaged alongside the other distributions. It is not in the BCANZ default set.

Changes

  • src/TMB/ll_invpareto_eur.hpp: negative log-likelihood, log-density log(shape) + log(scale) + (shape - 1) log y - (shape + 1) log(y + scale), censored branch via the closed-form CDF.
  • R/invpareto_eur.R: ssd_pinvpareto_eur(), ssd_qinvpareto_eur(), ssd_rinvpareto_eur(), ssd_einvpareto_eur(), starting values (shape = 1, scale = median), and the p/q backends. The CDF is exactly 0 for non-positive concentrations, the contract qdist() ignores bounded support at the extreme quantiles #195 established for invpareto.
  • dist_data: invpareto_eur with bcanz = FALSE, tails = TRUE, npars = 2, valid = TRUE, bound = FALSE. It therefore appears in ssd_dists_all() and ssd_dists_shiny().
  • ssd_pmulti()/ssd_qmulti()/ssd_rmulti() gain invpareto_eur.* arguments; params.R documents them.
  • Article: the inverse Pareto section describes both forms and how to fit each.
  • Tests: test-invpareto_eur.R covers test_dist(), agreement with actuar for p/q and the MLE, the anon_a and boron fits, ssd_hc()/ssd_hp() confidence limits, the clamp on non-positive concentrations, and model averaging with lnorm. Snapshots that enumerate all distributions are updated.

Verification

Merged with current dev. ssd_pinvpareto_eur() matches actuar::pinvpareto() exactly and the quantile to 1.6e-11. Fits are scale invariant: multiplying ccme_boron by 1000 leaves shape unchanged to seven digits and scales scale by exactly 1000. Endpoints follow #195: ssd_qinvpareto_eur(c(0, 1)) is 0, Inf and ssd_hc(fit, proportion = c(0, 1)) returns the same.

Full suite 1477 passing, 0 failures; R CMD check 0 errors, 0 warnings, 0 notes; air format --check clean.

Notes

The ssd_match_moments() snapshot changes for the existing distributions as well as gaining an invpareto_eur row: adding a distribution changes the order in which random draws are consumed under the fixed seed, as it did for ltriangle. Because tails = TRUE and valid = TRUE, ssd_dists_shiny() now lists invpareto_eur, so shinyssdtools will offer it once it picks up this release.

joethorley and others added 3 commits June 10, 2026 06:42
Add the European form of the inverse Pareto distribution as a new
user-selectable distribution `invpareto_eur`, and clarify that the
existing `invpareto` is the North American form.

The European version is unbounded above and uses the same shape/scale
parameterisation as `actuar::dinvpareto()`, making it a more realistic
stand-alone SSD than the bounded North American form. Its scale is a
free parameter estimated by maximum likelihood (no boundary fixing).

- Add TMB log-likelihood `ll_invpareto_eur` and register it.
- Add `ssd_pinvpareto_eur()`, `ssd_qinvpareto_eur()`,
  `ssd_rinvpareto_eur()`, `ssd_einvpareto_eur()` and internal
  helpers, mirroring `invpareto`.
- Register `invpareto_eur` in `dist_data` (bcanz = FALSE, valid = FALSE)
  so it is fitted in isolation like `invpareto`.
- Document the American vs European distinction in the distributions
  vignette and parameter docs.
- Add tests for both forms, including an independent check that the
  fitted mle and the p/q functions match the actuar parameterisation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mark `invpareto` and `invpareto_eur` as valid = TRUE in `dist_data` so
that both can be fitted alongside other distributions and enrolled in
model averaging, rather than only in isolation.

- Set valid = TRUE for both forms in `dist_data`.
- Add invpareto.* and invpareto_eur.* parameters to `ssd_pmulti()`,
  `ssd_qmulti()` and `ssd_rmulti()` so the model-averaging machinery
  accepts them.
- Update the distributions vignette: both forms can now be
  model-averaged, with a caution that the North American `invpareto`
  is bounded above so its contribution to upper-tail estimates should
  be interpreted with care.
- Update tests and snapshots: both forms now appear in
  `ssd_dists_all()`, `invpareto_eur` joins `ssd_dists_shiny()`,
  `ssd_emulti()` gains both forms, and the model-averaged cdf plots
  now include both. Replace the invpareto_eur isolation test with one
  confirming it can be fitted alongside other distributions.

Both forms remain excluded from the default (bcanz) candidate set and
receive zero weight in the default model-averaging skeleton, so default
results are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix the remaining test failures surfaced by R CMD check after marking
both inverse Pareto forms valid:

- Rewrite the `lnorm + invpareto` isolation test to confirm the
  combination now fits (the isolation rule no longer applies since
  there are no invalid-likelihood distributions).
- Update the `estimates(all_estimates = TRUE)` snapshot to include the
  new weight-0 invpareto and invpareto_eur entries.
- Update the `tidy_unstable_anon_e` snapshot now that
  `ssd_dists(bcanz = FALSE)` includes both invpareto forms.

Full R CMD check passes with 0 errors, 0 warnings, 0 notes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@joethorley
joethorley marked this pull request as draft June 10, 2026 15:24
@joethorley
joethorley changed the base branch from main to dev July 12, 2026 22:19
@joethorley joethorley closed this Jul 14, 2026
@joethorley joethorley reopened this Jul 14, 2026
joethorley and others added 7 commits July 14, 2026 15:39
Both inverse Pareto forms are bounded/limiting distributions whose
likelihoods are not comparable to the standard candidates for AICc model
averaging, so they must be fitted in isolation (valid=FALSE), matching the
long-standing treatment of the North American invpareto on dev.

- Revert invpareto valid TRUE->FALSE (the PR had inadvertently flipped it).
- Set invpareto_eur valid=FALSE.
- Update tests: invpareto_eur must be fitted in isolation; drop it from
  ssd_dists_shiny(); remove the added invpareto-with-others test.
- Regenerate dist_data and the valid-filtered snapshots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ructural assertions

The hc/hp bootstrap confidence-interval snapshots (hc_boron, hp_boron) are not
reproducible across platforms (bootstrap refits diverge with different
BLAS/LAPACK), so they failed on Linux/Windows CI. Assert structural properties
(finite, ordered confidence limits) instead. The exact snapshots are preserved
in the ssdtests package (poissonconsulting/ssdtests@add-invpareto-eur).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`(q / (q + scale))^shape` is only a CDF for q > 0. For negative q it is
negative, or positive for an even shape, so `ssd_pinvpareto_eur(-2)`
returned 8. Return exactly 0 on and below the lower support limit, the
same contract #195 established for the
bounded inverse Pareto.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The European inverse Pareto is a regular two-parameter distribution
with an interior maximum likelihood estimate, unlike the bounded North
American form whose scale sits on the data maximum, so there is no
reason to restrict it to being fitted in isolation. Register it with
`valid = TRUE`, which the distributions article already claimed.

It therefore joins `ssd_dists_all()` and `ssd_dists_shiny()`, the
`ssd_emulti()` defaults, and the fits-of-everything snapshots. The
`ssd_match_moments()` snapshot also shifts for the existing
distributions because adding a distribution changes the order in which
random draws are consumed under the fixed seed, as it did for
`ltriangle`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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