Source code for sequince.stats
from __future__ import annotations
from .array_api import asarray, logsumexp, namespace
from .state import normalize_log_weights
from .typing import Array
[docs]
def ess_from_log_weights(log_weights: Array) -> Array:
"""Return the effective sample size (ESS) as an array scalar."""
xp = namespace(log_weights)
lw = asarray(log_weights, xp=xp)
normalized_lw, _ = normalize_log_weights(lw, xp=xp)
weights = xp.exp(normalized_lw)
squared_weight_sum = xp.sum(xp.square(weights))
safe_sum = xp.where(squared_weight_sum > 0.0, squared_weight_sum, 1.0)
ess = 1.0 / safe_sum
return xp.where(squared_weight_sum > 0.0, ess, xp.nan)
[docs]
def ess_ratio_from_log_weights(log_weights: Array) -> Array:
"""Return ESS ratio (ESS / n) as an array scalar."""
ess = ess_from_log_weights(log_weights)
return ess / log_weights.shape[0]
[docs]
def cess_ratio_from_log_weights_and_increments(
log_weights: Array,
log_increments: Array,
) -> Array:
"""Return the conditional ESS ratio induced by log increments.
The quantity computed is
(sum_i W_i g_i)^2 / sum_i W_i (g_i)^2
where W_i are the normalized current weights and g_i are the proposed
incremental weights.
See e.g. Eq 13 in arXiv:1612.06468 for more details.
"""
xp = namespace(log_weights, log_increments)
lw = asarray(log_weights, xp=xp)
li = asarray(log_increments, xp=xp, like=lw)
log_norm = logsumexp(lw, xp=xp)
normalized_lw = lw - log_norm
log_num = 2.0 * logsumexp(normalized_lw + li, xp=xp)
log_den = logsumexp(normalized_lw + 2.0 * li, xp=xp)
return xp.exp(log_num - log_den)