Gaussian Likelihoods

This module provides the base classes for Gaussian likelihoods in SOLikeT, including support for combining multiple likelihoods with cross-covariances.

GaussianLikelihood

The base class for all Gaussian likelihoods. Subclasses should implement the _get_theory() method to compute the theory prediction.

class soliket.gaussian.GaussianLikelihood(info: Mapping[str, Any] = mappingproxy({}), name: str | None = None, timing: bool | None = None, packages_path: str | None = None, initialize=True, standalone=True)[source]

Bases: Likelihood

Base class for Gaussian likelihoods in SOLikeT.

This class provides the infrastructure for computing Gaussian log-likelihoods from SACC data files. Subclasses must implement the _get_theory() method to compute the theory prediction for the data vector.

Parameters

namestr

Name identifier for the likelihood (default: “Gaussian”)

datapathstr

Path to the SACC file containing data and covariance

use_spectrastr or list

Which spectra to use. Either “all” or a list of tracer pairs like [("tracer1", "tracer2")]

ncovsimsint, optional

Number of simulations used to estimate covariance. If provided, applies the Hartlap correction factor to the inverse covariance.

Attributes

dataGaussianData

The assembled Gaussian data object with covariance

sacc_datasacc.Sacc

The loaded SACC data object

xnp.ndarray

The bin centers (ell values)

ynp.ndarray

The data vector

covnp.ndarray

The covariance matrix

Examples

To create a custom Gaussian likelihood:

class MyLikelihood(GaussianLikelihood):
    name = "my_likelihood"
    _allowable_tracers = ("cmb_temperature", "cmb_polarization")

    def _get_theory(self, **params):
        # Compute theory prediction
        return theory_vector
logp(**params_values) float[source]

Computes and returns the log likelihood value. Takes as keyword arguments the parameter values. To get the derived parameters, pass a _derived keyword with an empty dictionary.

Alternatively you can just implement calculate() and save the log likelihood into state[‘logp’]; this may be more convenient if you also need to also calculate other quantities.

MultiGaussianLikelihood

A likelihood that combines multiple Gaussian likelihoods, optionally accounting for cross-covariances between them.

class soliket.gaussian.MultiGaussianLikelihood(info=mappingproxy({}), **kwargs)[source]

Bases: GaussianLikelihood

A likelihood combining multiple Gaussian likelihoods with cross-covariances.

This class enables joint analysis of multiple datasets by combining their data vectors and covariance matrices. Cross-covariances between datasets can be specified via a CrossCov object stored in SACC format.

Parameters

componentslist of str

List of likelihood class names to combine, e.g., ["soliket.mflike.MFLike", "soliket.lensing.LensingLikelihood"]

optionslist of dict

Configuration options for each component likelihood. Each dict should contain at minimum datapath and any other required parameters.

cross_cov_pathstr, optional

Path to a SACC file containing cross-covariances between components. If not provided, components are assumed independent (zero cross-covariance).

Attributes

likelihoodslist of Likelihood

The instantiated component likelihoods

cross_covCrossCov or None

The loaded cross-covariance container

dataMultiGaussianData

The combined data object with joint covariance

Examples

YAML configuration:

likelihood:
  soliket.MultiGaussianLikelihood:
    components:
      - soliket.mflike.MFLike
      - soliket.lensing.LensingLikelihood
    options:
      - datapath: /path/to/mflike.fits
        use_spectra: all
      - datapath: /path/to/lensing.fits
    cross_cov_path: /path/to/cross_cov.fits

Python usage:

from soliket import MultiGaussianLikelihood

info = {
    "components": ["soliket.mflike.MFLike", "soliket.lensing.LensingLikelihood"],
    "options": [
        {"datapath": "mflike.fits", "use_spectra": "all"},
        {"datapath": "lensing.fits"},
    ],
    "cross_cov_path": "cross_cov.fits",
}
like = MultiGaussianLikelihood(info)
classmethod get_defaults(return_yaml=False, yaml_expand_defaults=True, input_options=mappingproxy({}))[source]

Return defaults for this component_or_class, with syntax:

option: value
[...]

params:
  [...]  # if required

prior:
  [...]  # if required

If keyword return_yaml is set to True, it returns literally that, whereas if False (default), it returns the corresponding Python dict.

Note that in external components installed as zip_safe=True packages files cannot be accessed directly. In this case using !default .yaml includes currently does not work.

Also note that if you return a dictionary it may be modified (return a deep copy if you want to keep it).

if yaml_expand_defaults then !default: file includes will be expanded

input_options may be a dictionary of input options, e.g. in case default params are dynamically dependent on an input variable

get_helper_theories() dict[str, Theory][source]

Return dictionary of optional names and helper Theory instances that should be used in conjunction with this component. The helpers can be created here as only called once, and before any other use of helpers.

Returns:

dictionary of names and Theory instances

classmethod get_modified_defaults(defaults, input_options=mappingproxy({}))[source]

After defaults dictionary is loaded, you can dynamically modify them here as needed,e.g. to add or remove defaults[‘params’]. Use this when you don’t want the inheritance-recursive nature of get_defaults() or don’t only want to affect class attributes (like get_class_options() does0.

get_requirements()[source]

Get a dictionary of requirements (or a list of requirement name, option tuples) that are always needed (e.g. must be calculated by another component or provided as input parameters).

Returns:

dictionary or list of tuples of requirement names and options (or iterable of requirement names if no optional parameters are needed)

initialize_with_provider(provider: Provider)[source]

Final initialization after parameters, provider and assigned requirements set. The provider is used to get the requirements of this theory using provider.get_X() and provider.get_param(‘Y’).

Parameters:

provider – the theory.Provider instance that should be used by this component to get computed requirements

Usage Example

To combine multiple likelihoods (e.g., CMB TT and lensing) with cross-covariances:

likelihood:
  soliket.MultiGaussianLikelihood:
    components:
      - soliket.mflike.MFLike
      - soliket.lensing.LensingLikelihood
    options:
      - datapath: /path/to/mflike_data.fits
        use_spectra: all
      - datapath: /path/to/lensing_data.fits
    cross_cov_path: /path/to/cross_covariance.fits

The cross_cov_path parameter is optional. If not provided, the likelihoods are assumed to be independent (zero cross-covariance).

CrossCov

A container for storing cross-covariances between likelihood components. Supports saving and loading in SACC format.

class soliket.gaussian.CrossCov(*args, **kwargs)[source]

Bases: dict

Cross-covariance container for multi-component Gaussian likelihoods.

Stores cross-covariances between named components (e.g., “mflike”, “lensing”) and optionally the full covariances for each component. Supports saving and loading in SACC format for persistence.

The dictionary keys are tuples of component names, e.g., (“mflike”, “lensing”). Values are the corresponding covariance matrices.

For the full joint covariance, use:

  • Diagonal blocks: (name, name) -> auto-covariance matrix

  • Off-diagonal blocks: (name1, name2) -> cross-covariance matrix

Examples

Mode 1: Full covariance specification

Use add_component() for auto-covariances and add_cross_covariance() for off-diagonal blocks:

cross_cov = CrossCov()
cross_cov.add_component("mflike", mflike_cov)
cross_cov.add_component("lensing", lensing_cov)
cross_cov.add_cross_covariance("mflike", "lensing", cross_block)
cross_cov.save("cross_cov.fits")

Mode 2: Cross-covariance only

If auto-covariances will come from individual likelihoods:

cross_cov = CrossCov()
cross_cov.add_cross_covariance("mflike", "lensing", cross_block)
cross_cov.save("cross_cov.fits")

Loading:

cross_cov = CrossCov.load("cross_cov.fits")
block = cross_cov[("mflike", "lensing")]
add_component(name: str, cov: ndarray)[source]

Add a component with its full covariance.

Parameters

namestr

Component name (e.g., “mflike”, “kk”)

covnp.ndarray

Full covariance matrix for this component

add_cross_covariance(name1: str, name2: str, cross_cov: ndarray)[source]

Add cross-covariance between two components.

Parameters

name1str

First component name

name2str

Second component name

cross_covnp.ndarray

Cross-covariance matrix with shape (n1, n2)

add_metadata(key: tuple[str], tracers: tuple[tuple[str]], data_types: tuple[str], tracer_info: dict[str, dict[str, str | int]] = None)[source]

Store metadata for cross-covariance entries (legacy method).

Parameters

keytuple[str]

Component identifier key

tracerstuple[tuple[str]]

Tracer pairs for each component

data_typestuple[str]

Data types (e.g., “cl_00”, “cl_22”)

tracer_infodict[str, dict[str, str | int]]

Dictionary mapping tracer names to their properties

property component_names: list[str]

Get ordered list of component names.

classmethod load(path: str | None) CrossCov | None[source]

Load cross-covariance from SACC format.

Parameters

pathstr or None

Path to SACC file. If None, returns None.

Returns

CrossCov or None

Loaded cross-covariance object, or None if path is None.

save(path: str)[source]

Save cross-covariance to SACC format.

The SACC file will contain: - A misc tracer for each component - Dummy data points to establish the data vector structure - The full joint covariance matrix

Parameters

pathstr

Output path (must end with .fits or .sacc)

Usage Modes

Mode 1: Full covariance specification

Use add_component() to register each component with its auto-covariance, then add_cross_covariance() for off-diagonal blocks:

from soliket.gaussian import CrossCov

cross_cov = CrossCov()

# Add auto-covariances
cross_cov.add_component("mflike", mflike_cov)
cross_cov.add_component("lensing", lensing_cov)

# Add cross-covariance
cross_cov.add_cross_covariance("mflike", "lensing", mflike_lensing_cov)

# Save to SACC format
cross_cov.save("cross_covariance.fits")

Mode 2: Cross-covariance only

If you only want to specify the cross-covariance (using auto-covariances from individual likelihoods), just use add_cross_covariance():

cross_cov = CrossCov()
cross_cov.add_cross_covariance("mflike", "lensing", mflike_lensing_cov)
cross_cov.save("cross_covariance.fits")

When loaded by MultiGaussianLikelihood, the auto-covariances will be taken from each individual likelihood’s SACC file.

Loading CrossCov

To load a previously saved cross-covariance:

from soliket.gaussian import CrossCov

cross_cov = CrossCov.load("cross_covariance.fits")

# Access blocks
mflike_lensing_block = cross_cov[("mflike", "lensing")]

GaussianData

Low-level data container for named multivariate Gaussian data.

class soliket.gaussian.GaussianData(name, x: Sequence, y: Sequence[float], cov: ndarray, ncovsims: int | None = None, indices: ndarray | None = None)[source]

Bases: object

Container for named multivariate Gaussian data.

Stores a data vector with its covariance matrix and provides methods for computing the Gaussian log-likelihood.

Parameters

namestr

Name identifier for the data

xSequence

Labels or coordinates for each data point (e.g., ell values)

ySequence[float]

The data vector values

covnp.ndarray

Covariance matrix with shape (n, n) where n = len(x)

ncovsimsint, optional

Number of simulations used to estimate covariance. If provided, applies the Hartlap correction factor to the inverse covariance.

indicesnp.ndarray, optional

Boolean array for trimming cross-covariances when scale cuts are applied

Attributes

inv_covnp.ndarray

Inverse covariance matrix (with Hartlap correction if applicable)

norm_constfloat

Normalization constant for the Gaussian likelihood

Raises

ValueError

If dimensions of x, y, and cov are incompatible If covariance matrix has non-positive determinant

loglike(theory: ndarray) float[source]

Compute the Gaussian log-likelihood.

Parameters

theorynp.ndarray

Theory prediction vector with same length as data

Returns

float

Log-likelihood value including normalization constant

MultiGaussianData

Assembles multiple GaussianData objects into a joint data vector with combined covariance matrix.

class soliket.gaussian.MultiGaussianData(data_list: list[GaussianData], cross_covs: CrossCov | None = None)[source]

Bases: GaussianData

Combined Gaussian data from multiple components with cross-covariances.

Assembles multiple GaussianData objects into a single joint data vector with a combined covariance matrix that includes both auto-covariances and cross-covariances between components.

Parameters

data_listlist of GaussianData

Individual data objects to combine

cross_covsCrossCov, optional

Cross-covariance container. If None, components are assumed independent. Auto-covariances can come from either the CrossCov or the individual GaussianData objects (individual data takes precedence if CrossCov doesn’t contain auto-covariance for a component).

Attributes

data_listlist of GaussianData

The original individual data objects

nameslist of str

Names of all components

lengthslist of int

Data vector lengths for each component

labelslist of str

Component name for each element in the combined data vector

Examples

Combining two datasets with cross-covariance:

data1 = GaussianData("mflike", x1, y1, cov1)
data2 = GaussianData("lensing", x2, y2, cov2)

cross_cov = CrossCov()
cross_cov.add_cross_covariance("mflike", "lensing", cross_block)

multi_data = MultiGaussianData([data1, data2], cross_cov)

# Access combined properties
print(multi_data.cov.shape)  # (n1 + n2, n1 + n2)
loglike = multi_data.loglike(theory_vector)
loglike(theory: ndarray) float[source]

Compute the Gaussian log-likelihood.

Parameters

theorynp.ndarray

Theory prediction vector with same length as data

Returns

float

Log-likelihood value including normalization constant