Primitives¶
The distribution math as standalone pure JAX functions — for custom
likelihoods, vmapped parameter grids, and non-stationary fields where a
distribution object would be in the way. Every family exposes the same core
set (log_prob, cdf, icdf, mean, return_level), so switching tail
behaviour is a rename rather than a rewrite.
All functions take parameters positionally as (x, loc, scale, shape) and
broadcast over them, so you can evaluate a whole spatial field of parameters
in one call.
Generalized Extreme Value (GEV)¶
The block-maxima workhorse. The concentration \(\xi\) spans all three tail
types smoothly, and the \(\xi \to 0\) Gumbel limit is handled with a numerically
stable branch rather than a discontinuity. Survival functions come in linear
and log forms — use gev_log_survival in the far tail where \(1 - F(x)\)
underflows.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
gev_log_prob(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Log PDF of the Generalized Extreme Value distribution.
Source code in src/xtremax/primitives/gev.py
gev_cdf(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
CDF of the Generalized Extreme Value distribution.
Source code in src/xtremax/primitives/gev.py
gev_icdf(q: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Quantile function (inverse CDF) of the GEV distribution.
Source code in src/xtremax/primitives/gev.py
gev_survival(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Survival function :math:S(x) = 1 - F(x) of the GEV distribution.
Uses -expm1(log F) rather than 1 - F so the deep upper tail
(where :math:F \approx 1 and :math:S is tiny) stays accurate
instead of cancelling against 1.0.
Source code in src/xtremax/primitives/gev.py
gev_log_survival(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Log survival function :math:\log S(x) = \log(1 - F(x)) of the GEV.
Source code in src/xtremax/primitives/gev.py
gev_mean(loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Mean of the GEV distribution (+inf when :math:\xi \ge 1).
.. math:: \mathbb{E}[X] = \mu + \sigma\,\frac{\Gamma(1 - \xi) - 1}{\xi} = \mu + \sigma\,\frac{\mathrm{expm1}(\log\Gamma(1 - \xi))}{\xi}
The expm1 form avoids the catastrophic Γ(1 - ξ) - 1 cancellation
for small ξ (which otherwise makes the mean wildly wrong in float32);
a Taylor branch covers the immediate neighbourhood of ξ = 0 where the
quotient is 0/0.
Source code in src/xtremax/primitives/gev.py
gev_return_level(period: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
T-period return level: :math:z_T = F^{-1}(1 - 1/T).
Parameterized by :math:-\log(1 - 1/T) = -\mathrm{log1p}(-1/T) so the
quantile stays accurate for large T (where 1 - 1/T rounds to 1 and
log(1 - 1/T) would lose all its precision).
Source code in src/xtremax/primitives/gev.py
Generalized Pareto (GPD)¶
The peaks-over-threshold counterpart, defined on exceedances above a threshold
(so loc = 0 by convention). Same structure as the GEV family, including the
log-survival form for deep-tail work.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
gpd_log_prob(x: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Log PDF of the Generalized Pareto Distribution (loc = 0).
Source code in src/xtremax/primitives/gpd.py
gpd_cdf(x: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
CDF of the Generalized Pareto Distribution.
Source code in src/xtremax/primitives/gpd.py
gpd_icdf(q: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Quantile function (inverse CDF) of the GPD.
Source code in src/xtremax/primitives/gpd.py
gpd_survival(x: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Survival function :math:S(x) = (1 + \xi x/\sigma)^{-1/\xi} of the GPD.
Computed as exp(-w) directly (rather than 1 - cdf) so the deep tail
stays accurate. Equals exp(-x/σ) in the exponential limit.
Source code in src/xtremax/primitives/gpd.py
gpd_log_survival(x: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Log survival :math:\log S(x) = -\tfrac{1}{\xi}\log(1 + \xi x/\sigma).
Equals -w inside the support, so the deep tail is exact instead of
passing through log(1 - cdf).
Source code in src/xtremax/primitives/gpd.py
gpd_mean(scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
GPD mean: :math:\sigma / (1 - \xi) for :math:\xi < 1, else +inf.
Source code in src/xtremax/primitives/gpd.py
gpd_return_level(period: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
T-period return level: :math:Q(1 - 1/T).
Parameterized by the exceedance probability 1/T directly (log p =
-log T) so it stays accurate for large T.
Source code in src/xtremax/primitives/gpd.py
Gumbel — GEV Type I¶
The \(\xi = 0\) case: exponential tails, closed-form moments (\(\mu + \sigma\gamma_E\)), and no shape parameter to estimate.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
gumbel_log_prob(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...]) -> Float[Array, ...]
¶
Gumbel log PDF: :math:-\log\sigma - z - e^{-z}, :math:z=(x-\mu)/\sigma.
Source code in src/xtremax/primitives/gumbel.py
gumbel_cdf(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...]) -> Float[Array, ...]
¶
Gumbel CDF: :math:F(x) = \exp(-\exp(-z)).
gumbel_icdf(q: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...]) -> Float[Array, ...]
¶
Gumbel quantile: :math:Q(p) = \mu - \sigma\log(-\log p).
gumbel_mean(loc: Float[Array, ...], scale: Float[Array, ...]) -> Float[Array, ...]
¶
gumbel_return_level(period: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...]) -> Float[Array, ...]
¶
T-period return level: :math:Q(1 - 1/T).
Fréchet — GEV Type II¶
The \(\xi > 0\) case: heavy polynomial tails and lower-bounded support. The mean
diverges once \(\xi \ge 1\), and frechet_mean returns +inf there rather than
a silently wrong number.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
frechet_log_prob(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Fréchet log PDF (assumes shape > 0).
Source code in src/xtremax/primitives/frechet.py
frechet_cdf(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
frechet_icdf(q: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Fréchet quantile function.
frechet_mean(loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Fréchet mean (+inf when shape >= 1).
frechet_return_level(period: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
T-period return level.
Source code in src/xtremax/primitives/frechet.py
Weibull (reverse) — GEV Type III¶
The \(\xi < 0\) case: a bounded upper tail, for quantities with a physical ceiling. Moments are always finite.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
weibull_log_prob(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Reverse-Weibull log PDF (assumes shape < 0).
Source code in src/xtremax/primitives/weibull.py
weibull_cdf(x: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
weibull_icdf(q: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Reverse-Weibull quantile function.
weibull_mean(loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
Reverse-Weibull mean (always finite for shape < 0).
weibull_return_level(period: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...]) -> Float[Array, ...]
¶
T-period return level.
Source code in src/xtremax/primitives/weibull.py
Non-stationary EVT¶
Under a changing climate the return level is no longer a single number — the GEV parameters become functions of covariates, and "the 100-year event" has to be re-stated per year or per scenario. These helpers build covariate design matrices, assemble spatio-temporal parameter fields, and invert between return levels and return periods for both stationary and non-stationary fields.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
design_matrix(covariates: Float[Array, ...]) -> Float[Array, ...]
¶
Prepend an intercept column to a static-covariate matrix.
.. math:: X(s) = [1, z_1(s), \ldots, z_D(s)]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
covariates
|
Float[Array, ...]
|
Static site covariates of shape |
required |
Returns:
| Type | Description |
|---|---|
Float[Array, ...]
|
Design matrix of shape |
Float[Array, ...]
|
column is all ones. |
Source code in src/xtremax/primitives/spatial.py
assemble_nonstationary_gev_fields(mu0: Float[Array, ...], mu1: Float[Array, ...], log_sigma: Float[Array, ...], shape: Float[Array, ...], time_covariate: Float[Array, ...]) -> tuple[Float[Array, ...], Float[Array, ...], Float[Array, ...]]
¶
Build non-stationary spatio-temporal GEV parameter fields.
Combines per-site intercept, trend, and log-scale fields with a temporal covariate into block-by-site GEV parameters:
.. math::
\mu_t(s) &= \mu_0(s) + \sum_k x_{t,k}\,\mu_{1,k}(s) \\
\sigma_t(s) &= \exp(\eta_\sigma(s)) \\
\xi_t(s) &= \xi
The scale is constant in time and the shape is broadcast from a scalar or per-site value; only the location varies with the covariate. This is the parameterization underneath hierarchical non-stationary GEV models, decoupled from any particular prior / GP / regression machinery.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mu0
|
Float[Array, ...]
|
Spatial intercept :math: |
required |
mu1
|
Float[Array, ...]
|
Trend coefficient field of shape |
required |
log_sigma
|
Float[Array, ...]
|
Log-scale field :math: |
required |
shape
|
Float[Array, ...]
|
GEV shape :math: |
required |
time_covariate
|
Float[Array, ...]
|
Temporal covariate of shape |
required |
Returns:
| Type | Description |
|---|---|
Float[Array, ...]
|
Tuple |
Float[Array, ...]
|
|
Source code in src/xtremax/primitives/nonstationary.py
nonstationary_return_level(return_period: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...], time_axis: int | None = None, num_bisection_steps: int = 64, lower: Float[Array, ...] | None = None, upper: Float[Array, ...] | None = None) -> Float[Array, ...]
¶
Return level for stationary or non-stationary GEV parameter fields.
Stationary (time_axis is None) uses the closed-form quantile
:math:z_T = F^{-1}(1 - 1/T).
Non-stationary (time_axis given): there is no single closed-form
quantile because the parameters vary by block, so z_T is found by
bisection such that the expected number of exceedances over the supplied
blocks equals :math:N_\text{blocks} / T:
.. math:: \sum_t \Pr(Y_t > z_T) = N_\text{blocks} / T.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_period
|
Float[Array, ...]
|
Return period :math: |
required |
loc
|
Float[Array, ...]
|
GEV location field. |
required |
scale
|
Float[Array, ...]
|
GEV scale field. |
required |
shape
|
Float[Array, ...]
|
GEV shape field. |
required |
time_axis
|
int | None
|
Axis indexing blocks, or |
None
|
num_bisection_steps
|
int
|
Bisection iterations for the non-stationary solve. |
64
|
lower
|
Float[Array, ...] | None
|
Optional lower bracket for the non-stationary solve. Defaults
to a conservative value derived from |
None
|
upper
|
Float[Array, ...] | None
|
Optional starting upper bracket. It is grown automatically until it brackets the root, so an underestimate (including the default) is corrected rather than silently returned. |
None
|
Returns:
| Type | Description |
|---|---|
Float[Array, ...]
|
Return level :math: |
Source code in src/xtremax/primitives/nonstationary.py
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | |
nonstationary_return_period(threshold: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...], time_axis: int | None = None) -> Float[Array, ...]
¶
Return period associated with a threshold under (non-)stationary GEV.
Stationary (time_axis is None):
.. math:: T(z) = 1 / \Pr(Y > z).
Non-stationary (time_axis given): the effective return period from
the average exceedance rate over the supplied blocks,
.. math:: T_\text{eff}(z) = N_\text{blocks} / \sum_t \Pr(Y_t > z).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
threshold
|
Float[Array, ...]
|
Threshold |
required |
loc
|
Float[Array, ...]
|
GEV location field. |
required |
scale
|
Float[Array, ...]
|
GEV scale field. |
required |
shape
|
Float[Array, ...]
|
GEV shape field. |
required |
time_axis
|
int | None
|
Axis indexing blocks, or |
None
|
Returns:
| Type | Description |
|---|---|
Float[Array, ...]
|
Return period with the shape of the non-time dimensions. |
Source code in src/xtremax/primitives/nonstationary.py
expected_exceedances(threshold: Float[Array, ...], loc: Float[Array, ...], scale: Float[Array, ...], shape: Float[Array, ...], time_axis: int | None = None) -> Float[Array, ...]
¶
Expected number of block exceedances of a threshold.
For GEV block maxima the per-block exceedance probability is the
survival function :math:\Pr(Y_t > z) = 1 - F(z). Summing over blocks
gives the expected number of exceedances:
.. math:: \Lambda(z) = \sum_t \Pr(Y_t > z).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
threshold
|
Float[Array, ...]
|
Threshold / candidate return level |
required |
loc
|
Float[Array, ...]
|
GEV location field. |
required |
scale
|
Float[Array, ...]
|
GEV scale field. |
required |
shape
|
Float[Array, ...]
|
GEV shape field. |
required |
time_axis
|
int | None
|
Axis indexing blocks. If |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Either |
Float[Array, ...]
|
math: |
Float[Array, ...]
|
math: |
Source code in src/xtremax/primitives/nonstationary.py
Spatial helpers¶
Building blocks for spatial pooling: a distance matrix between sites and a two-range exponential correlation used as a GP covariance for parameter fields.
Pure-JAX primitive functions for extreme value distributions.
Every function takes arrays and returns arrays. No NumPyro, no class
state, no side effects — compatible with jax.jit, jax.grad, and
jax.vmap.
The Distribution classes in :mod:xtremax.distributions are thin
wrappers that route log_prob / cdf / icdf / mean /
return_level to these primitives.
pairwise_distances(coords: Float[Array, ...]) -> Float[Array, ...]
¶
Euclidean distance matrix between sites.
.. math:: D_{ij} = \lVert s_i - s_j \rVert_2
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coords
|
Float[Array, ...]
|
Site coordinates of shape |
required |
Returns:
| Type | Description |
|---|---|
Float[Array, ...]
|
Dense distance matrix of shape |
Float[Array, ...]
|
diagonal. |
Source code in src/xtremax/primitives/spatial.py
two_range_correlation(dist_matrix: Float[Array, ...], weight: Float[Array, ...], range_short: Float[Array, ...], range_long: Float[Array, ...], jitter: float = 1e-06) -> Float[Array, ...]
¶
Two-range exponential correlation matrix with unit diagonal.
Convex mixture of two exponential dependence ranges, used as the correlation structure of a Gaussian copula over sites:
.. math:: \rho(h) = c_0 \exp(-h / c_1) + (1 - c_0) \exp(-h / c_2)
where h is the inter-site distance, c_0 = weight mixes the
short and long ranges, and c_1 = range_short / c_2 = range_long
are the two correlation length scales. The diagonal is renormalized to
exactly one (after adding jitter for positive-definiteness) so the
result is a valid correlation matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dist_matrix
|
Float[Array, ...]
|
Pairwise distances of shape |
required |
weight
|
Float[Array, ...]
|
Mixture weight :math: |
required |
range_short
|
Float[Array, ...]
|
Short correlation length scale :math: |
required |
range_long
|
Float[Array, ...]
|
Long correlation length scale :math: |
required |
jitter
|
float
|
Small positive diagonal inflation added before renormalization for numerical stability. |
1e-06
|
Returns:
| Type | Description |
|---|---|
Float[Array, ...]
|
Correlation matrix of shape |