derivkit.forecasting.expansions module#

Utilities for evaluating Fisher and DALI likelihood expansions.

This module provides functional helpers to evaluate approximate likelihoods (or posterior) surfaces from forecast tensors.

Conventions#

This module uses a single convention throughout:

  • delta_chi2 is defined from the displacement d = theta - theta0.

  • The log posterior is returned (up to an additive constant) as:

    log p(theta) = logprior(theta) - 0.5 * delta_chi2(theta)
    

With the forecast tensors returned by derivkit.forecasting.get_forecast_tensors() (using the introduced-at-order convention):

  • dali[1] == (F,)

  • dali[2] == (D1, D2)

  • dali[3] == (T1, T2, T3)

the DALI delta_chi2 is:

  • order 1 (Fisher): d.T @ F @ d

  • order 2 (doublet): add (1/3) D1[d,d,d] + (1/12) D2[d,d,d,d]

  • order 3 (triplet): add (1/3) T1[d^4] + (1/6) T2[d^5] + (1/36) T3[d^6]

GetDist convention#

GetDist expects loglikes to be the negative log posterior, up to a constant. Since this module defines:

log p = logprior - 0.5 * delta_chi2 + const

a compatible choice for GetDist is:

loglikes = -logprior + 0.5 * delta_chi2

(optionally shifted by an additive constant for numerical stability).

derivkit.forecasting.expansions.build_delta_chi2_dali(theta: ndarray[tuple[Any, ...], dtype[floating]], theta0: ndarray[tuple[Any, ...], dtype[floating]], dali: Any, *, forecast_order: int | None = 2) float#

Compute delta_chi2 under the DALI approximation.

This evaluates a scalar delta_chi2 from the displacement d = theta - theta0 using forecast tensors returned by derivkit.forecasting.get_forecast_tensors().

The input must be the dict form using the introduced-at-order convention:

  • dali[1] == (F,) with F of shape (p, p)

  • dali[2] == (D1, D2) with shapes (p, p, p) and (p, p, p, p)

  • dali[3] == (T1, T2, T3) with shapes (p,)*4, (p,)*5, (p,)*6

The evaluated quantity is:

  • order 2: d.T @ F @ d + (1/3) D1[d^3] + (1/12) D2[d^4]

  • order 3: order 2 plus (1/3) T1[d^4] + (1/6) T2[d^5] + (1/36) T3[d^6].

Parameters:
  • theta – Evaluation point in parameter space.

  • theta0 – Expansion point (fiducial parameters).

  • dali – Forecast tensors as a dict.

  • forecast_order – Maximum order to include. If None, uses the highest key in dali and requires it to be at least 2.

Returns:

Scalar delta_chi2.

Raises:
  • TypeError – If dali is not a dict.

  • ValueError – If required tensor orders are missing or have incompatible shapes.

derivkit.forecasting.expansions.build_delta_chi2_fisher(theta: ndarray[tuple[Any, ...], dtype[floating]], theta0: ndarray[tuple[Any, ...], dtype[floating]], fisher: ndarray[tuple[Any, ...], dtype[floating]]) float#

Computes a displacement chi-squared under the Fisher approximation.

Parameters:
  • theta – Evaluation point in parameter space. This is the trial parameter vector at which the Fisher expansion is evaluated.

  • theta0 – Expansion point (reference parameter vector). The Fisher matrix is assumed to have been computed at this point, and the expansion is taken in the displacement theta - theta0.

  • fisher – Fisher matrix with shape (p, p) with p the number of parameters.

Returns:

The scalar delta chi-squared value between theta and theta_0.

derivkit.forecasting.expansions.build_logposterior_dali(theta: ndarray[tuple[Any, ...], dtype[floating]], theta0: ndarray[tuple[Any, ...], dtype[floating]], dali: Any, *, forecast_order: int | None = 2, prior_terms: Sequence[tuple[str, dict[str, Any]] | dict[str, Any]] | None = None, prior_bounds: Sequence[tuple[float | None, float | None]] | None = None, logprior: Callable[[ndarray[tuple[Any, ...], dtype[floating]]], float] | None = None) float#

Compute the log posterior under the DALI approximation.

The posterior is evaluated as:

log p(theta) = logprior(theta) - 0.5 * delta_chi2(theta)

where delta_chi2 is computed from the dict-form forecast tensors dali using build_delta_chi2_dali().

Parameters:
  • theta – Evaluation point in parameter space.

  • theta0 – Expansion point (fiducial parameters).

  • dali – Forecast tensors as a dict in the introduced-at-order convention.

  • forecast_order – Maximum order to include in delta_chi2. If None, uses the highest key in dali.

  • prior_terms – Prior term specification passed to build_prior().

  • prior_bounds – Global hard bounds passed to build_prior().

  • logprior – Optional custom log-prior callable.

Returns:

Scalar log posterior value (up to an additive constant). If the prior evaluates to a non-finite value, returns -np.inf.

derivkit.forecasting.expansions.build_logposterior_fisher(theta: ndarray[tuple[Any, ...], dtype[floating]], theta0: ndarray[tuple[Any, ...], dtype[floating]], fisher: ndarray[tuple[Any, ...], dtype[floating]], *, prior_terms: Sequence[tuple[str, dict[str, Any]] | dict[str, Any]] | None = None, prior_bounds: Sequence[tuple[float | None, float | None]] | None = None, logprior: Callable[[ndarray[tuple[Any, ...], dtype[floating]]], float] | None = None) float#

Computes the log posterior under the Fisher approximation.

The returned value is defined up to an additive constant in log space. This corresponds to an overall multiplicative normalization of the posterior density in probability space.

If no prior is provided, this returns the Fisher log-likelihoods expansion with a flat prior and no hard cutoffs.

The Fisher approximation corresponds to a purely quadratic delta_chi2 surface:

delta_chi2 = d.T @ F @ d

so the log posterior is:

log p = -0.5 * delta_chi2

This normalization is equivalent to the convention="delta_chi2" used for DALI. In this interpretation, fixed delta_chi2 values correspond to fixed probability content (e.g. 68%, 95%) in parameter space, as for a Gaussian likelihoods. See derivkit.forecasting.expansions.delta_chi2_dali() for the corresponding DALI definition of delta_chi2 and its supported conventions.

Unlike the DALI case, there is no alternative normalization for the Fisher approximation: the likelihoods is strictly Gaussian and fully described by the quadratic form.

Parameters:
  • theta – Evaluation point in parameter space. This is the trial parameter vector at which the Fisher/DALI expansion is evaluated.

  • theta0 – Expansion point (reference parameter vector). The Fisher matrix and any DALI tensors are assumed to have been computed at this point, and the expansion is taken in the displacement theta - theta0.

  • fisher – Fisher matrix with shape (p, p) with p the number of parameters.

  • prior_terms – prior term specification passed to derivkit.forecasting.priors.core.build_prior().

  • prior_bounds – Global hard bounds passed to derivkit.forecasting.priors.core.build_prior().

  • logprior – Optional custom log-prior callable. If it returns a non-finite value, the posterior is treated as zero at that point and the function returns -np.inf.

Returns:

Scalar log posterior value, defined up to an additive constant.

derivkit.forecasting.expansions.build_subspace(idx: Sequence[int], *, theta0: ndarray[tuple[Any, ...], dtype[floating]], fisher: ndarray[tuple[Any, ...], dtype[floating]] | None = None, dali: dict[int, tuple[ndarray[tuple[Any, ...], dtype[floating]], ...]] | None = None) dict[str, Any]#

Extracts a parameter subspace for Fisher or DALI expansions.

This returns a slice through parameter space: parameters not in idx are held fixed at their expansion values. This is not a marginalization.

Provide exactly one of fisher or dali:

  • Fisher: fisher has shape (p, p) and the return dict contains {"theta0": theta0_sub, "fisher": fisher_sub}.

  • DALI: dali is the dict form returned by derivkit.forecasting.get_forecast_tensors() using the introduced-at-order convention, and the return dict contains {"theta0": theta0_sub, "dali": dali_sub}.

Parameters:
  • idx – Parameter indices to extract.

  • theta0 – Expansion point of shape (p,).

  • fisher – Fisher matrix of shape (p, p).

  • dali – Forecast tensors as a dict mapping order -> multiplet.

Returns:

A dict containing the sliced objects. Always includes "theta0". Includes "fisher" if fisher was provided, or "dali" if dali was provided.

Raises:
  • ValueError – If not exactly one of fisher or dali is provided.

  • TypeError – If idx contains non-integers, or if dali is not a dict.

  • IndexError – If any index in idx is out of bounds.

  • ValueError – If the provided arrays have incompatible shapes.