Skip to content

Profile likelihoods

A profile likelihood fixes one parameter \(\theta\) on a grid and, at each grid value, finds the best fit over all the others:

\[ \chi^2_\mathrm{prof}(\theta) = -2 \max_{\phi} \log L(\theta, \phi), \qquad \Delta\chi^2 = \chi^2_\mathrm{prof} - \chi^2_\mathrm{min}. \]

Unlike a marginalised posterior, it does not depend on the prior volume of the other parameters. That matters when a posterior is pulled by prior volume (for example by \(\sum m_\nu\) near zero, or by early dark energy). For a single Gaussian parameter, \(\Delta\chi^2 \le 1\) is the 68% interval and \(\Delta\chi^2 \le 4\) is the 95% one.

How cosmonuts computes it

Every grid point and every start runs as one batched L-BFGS call, the same compiled program as cosmonuts maximize, on CPU or GPU. It does not step along the grid one point at a time. A 41-point profile with 4 starts per point is a single call of 164 gradient-based optimisations.

  1. The global best fit is found first. Every grid point starts from it, with the profiled parameter set to the grid value, and from num_starts - 1 draws from the prior.
  2. Sweeps then restart each grid point from its neighbours' optima and keep whichever is better. They repeat until no point improves (at most sweeps times). A grid point stuck in a local minimum shows up as a kink, and a neighbour's solution removes it.
  3. If a grid point does better than the global best fit, it becomes the reference \(\chi^2_\mathrm{min}\).

By default the priors are left out (ignore_prior: true), which is the frequentist profile. Set ignore_prior: false (--keep-prior on the command line) to keep them, for example Gaussian priors on nuisance parameters.

Example: \(w_0\) from DESI DR2 BAO and the Planck PR4 CMB

Add a profile block to the run file. examples/w0wacdm_desi_dr2_cmb.yaml has one:

profile:
  params: {w0: {min: -1.4, max: -0.2, n: 41}}   # or w0: [values...]; two parameters for a 2-D grid
  num_starts: 4                                 # per grid point: the best fit, then prior draws
  sweeps: 3                                     # neighbour restarts (0: none)
cosmonuts profile examples/w0wacdm_desi_dr2_cmb.yaml
cosmonuts profile examples/w0wacdm_desi_dr2_cmb.yaml -p wa=-2.5:0.5:31 -f   # another grid
uv run --group plots cosmonuts plot profile chains/examples/w0wacdm_desi_dr2_cmb
import numpy as np
from cosmonuts.config import run_profile
from cosmonuts.profile import profile

model, prof, paths = run_profile("examples/w0wacdm_desi_dr2_cmb.yaml")
# or, on any Model:
prof = profile(model, {"w0": np.linspace(-1.4, -0.2, 41)}, num_starts=4)
prof.delta_chi2          # one value per grid point
prof.interval(1.0)       # (lower, upper); None on a side the grid leaves open
prof.params["wa"]        # every parameter at each grid point's optimum

With an output, a run writes

  • <output>.profile.txt: one row per grid point, with the profiled parameter(s), chi2, delta_chi2, converged, chi2__<likelihood> for each likelihood, and then the other parameters;
  • <output>.profile.yaml: the global best fit, \(\chi^2_\mathrm{min}\), the \(\Delta\chi^2 = 1, 4\) intervals and the settings.

Things to check

  • Convergence. The table and cosmonuts plot profile report the grid points whose best start did not reach the gradient tolerance. Raise max_steps or loosen tol for them.
  • Warnings. A run warns (in the summary, in .profile.yaml and as Python UserWarnings) in two cases. The first is when the sweeps stop at the sweeps limit while still improving points; raise sweeps. The second is when grid points lie above the trends of both of their neighbours (marked suspect in the table). A true profile is the lower envelope of smooth branches, so such points are fits left in a worse local minimum. That often means the likelihood has a narrow second valley. Raise num_starts, and look at the model there. In w0waCDM, for example, a valley at \(w_0 + w_a > 0\) appears where the CMB compression no longer holds, and examples/w0wacdm_desi_dr2_cmb_w0pwa.yaml samples \(w_0 + w_a < 0\) to remove it.
  • Grid edges. Grid values must lie strictly inside a uniform prior. An interval that reaches the grid's edge is reported as open, so widen the grid.
  • Two parameters. profile.params with two entries profiles over their outer product. cosmonuts plot profile draws 1-D profiles only for now.