gallery.GalleryDiagonal

Next year’s diagonal from a fitted gallery entry’s posterior predictive.

Usage

Source

gallery.GalleryDiagonal(
    entry,
    cells,
    field=None,
)

entry is anything with ~ibnr.gallery.entry.PredictsHeldout - a fitted single-cohort entry, or the per-cohort view a pooled NN entry returns from at_cohort(segment). cells is the ~ibnr.kernels.holdout.HoldoutCells from gallery.next_diagonal(...), the same object the leaderboard scores at. field names which loss field to re-reserve when the cells carry more than one (compartmental scores paid and reported together); with a single field it is inferred and must not be repeated.

The alignment is checked against the fit, not assumed. A MackFit, a HoldoutCells and a fitted entry are three objects built by three calls, and nothing about their types says they describe the same cohort at the same cutoff on the same field off the same history. Handed a mismatched set, rereserve would happily return a complete page of plausible dollars. So check() requires, for every OPEN origin of the fit, exactly one scorable cell, at the development lag one step past that origin’s diagonal, whose prev_value equals the fit’s own latest-diagonal cell. That comparison is load-bearing: the predecessor of the held-out cell and the fit’s diagonal are the same number read by two different code paths, so requiring them equal catches a wrong cutoff, a wrong field, a wrong cohort and a wrong grain in one check.

It does not catch a wrong history, which is why _require_same_training_history() exists as a separate third leg - the first two tie the CELLS to the fit and leave the ENTRY unbound to either.

An excluded cell is fatal here, and is not on a leaderboard. A cohort whose next diagonal is short a cell simply scores on fewer cells for CRPS - align_panel prices that in panel.dropped and moves on. A CDR cannot: a missing diagonal cell is not a smaller diagonal, it is an origin whose re-reserved ultimate would silently be taken as zero and whose whole estimated ultimate would then be reported as one year’s development result. Hence a refusal naming the origin and the exclusion counts.

Nothing here constrains the sign of a draw. A distributional head with unbounded support can draw a negative cumulative, which re-reserves into a meaningless factor. That is the entry’s property, not this class’s, and it is left visible rather than clipped - the same stance kernels.mack.PROCESS_LAWS takes when it documents that only gamma and lognormal guarantee a positive diagonal. Check mean_cdr against the fit’s reserve before believing a tail.

Parameter Attributes

entry: PredictsHeldout
cells: HoldoutCells
field: str | None = None

Methods

Name Description
check() Every alignment refusal, before a single posterior draw is touched.
draw() (n_draws, n_w) cumulative loss on next year’s diagonal, zero at
resolve_n_draws() None - the posterior’s own size, whatever it is.

check()

Every alignment refusal, before a single posterior draw is touched.

Usage

Source

check(fit)

Deliberately does NOT call fit.require_positive_open_diagonals(). That is Mack’s precondition - his conditional variance is proportional to the diagonal cell - and it is no more this generator’s than it is the bootstrap’s. What an entry needs of the diagonal is whatever it needed to fit; the fit already happened.


draw()

(n_draws, n_w) cumulative loss on next year’s diagonal, zero at

Usage

Source

draw(fit, *, n_draws, rng)

closed origins.

The entry is seeded FROM rng rather than from a seed of its own, so simulate_one_year_cdr(..., seed=s) remains the single control on reproducibility - a second seed on this class would be a second thing to set and a silent way for two “identical” runs to differ.


resolve_n_draws()

None - the posterior’s own size, whatever it is.

Usage

Source

resolve_n_draws(requested)

The base class resolves None to a Monte Carlo budget because for mack and odp_bootstrap the draw count is one: ask for more diagonals and you get more. Here the draws come from a posterior that was sized at fit time, and asking for 20,000 could only mean resampling them with replacement - Monte Carlo noise added on top of the posterior, and a 99.5th percentile that appears to rest on 100 observations when it rests on however many distinct draws there really were.

The same applies, for a different reason, to an entry whose draws are a SIMULATION rather than a posterior - clark’s parametric bootstrap, an NN mixture head. Those could in principle produce any count, but PredictsHeldout._draws_native(cells, rng) takes no count argument, so there is no way to ask; the number is fixed by the entry’s own configuration either way.

An explicit count is not ignored - draw() refuses one it cannot honour, rather than letting it sit there inert.