Likelihoods
Input: specifying likelihoods to explore
Likelihoods are specified under the likelihood block of your input .yaml file, together with their options:
likelihood:
[likelihood 1]:
[option 1]: [value 1]
[...]
[likelihood 2]:
[option 1]: [value 1]
[...]
Likelihood parameters are specified within the params
block, as explained in Parameters and priors.
cobaya comes with a number of internal general and cosmological likelihoods. You can also define your external likelihoods with simple Python functions, or by implementing a Python class defined in an external module. If your likelihood is just a simple Python functions, using an external function can be convenient. Any likelihood using data files or with more complex dependencies is best implemented as a new likelihood class.
External likelihood functions
External likelihood functions can be used by using input of the form:
likelihood:
# Simple way (does not admit additional options)
my_lik_1: [definition]
# Alternative way (can also take speeds, etc)
my_lik_1:
external: [definition]
speed: [...]
[more options]
The [definition]
follows the exact same rules as external priors, so check out that section for the details.
The only difference with external priors is that external likelihoods can provide derived parameters. To do that:
In your function, return a tuple of the log-likelihood and a dictionary of derived parameter values
{derived_1: value_1, [...]}
.When preparing Cobaya’s input, add to your external likelihood info an option
output_params
listing the names of the available derived parameters.
For an application, check out the advanced example.
If your external likelihood needs the products of a theory code:
In your function definition, define a keyword argument
_self
through which at runtime you will get access to an instance of the Cobaya likelihood wrapper of your function.When preparing Cobaya’s input, add to your external likelihood info an option
requires
stating the requirements of your likelihood.At run-time, you can call
get_[...]
methods of_self.provider
to get the requested quantities.
For an application, check out Creating your own cosmological likelihood.
Note
Obviously, _self
is a reserved parameter name that you cannot use as an argument in your likelihood definition, except for the purposes explained above.
Note
The input parameters of an external function are guessed from its definition. But in some cases you may prefer not to define your likelihood function with explicit arguments (e.g. if the number of them may vary). In that case, you can manually specify the input parameters via the input_params
option of the likelihood definition in your input dictionary.
E.g. the following two snippets are equivalent, but in the second one, one can alter the input parameters programmatically:
# Default: guessed from function signature
def my_like(a0, a1):
logp = # some function of `(a0, a1)`
devived = {"sum_a": a0 + a1}
return logp, derived
info_like = {"my_likelihood": {
"external": my_like, "output_params": ["sum_a"]}}
# Manual: no explicit function signature required
# Define the lists of input params
my_input_params = ["a0", "a1"]
def my_like(**kwargs):
current_input_values = [kwargs[p] for p in my_input_params]
logp = # some function of the input params
derived = {"sum_a": sum(current_input_values)}
return logp, derived
info_like = {"my_likelihood": {
"external": my_like,
"input_params": my_input_params, "output_params": ["sum_a"]}}
Likelihood classes: code conventions and defaults
Each likelihood inherits from the likelihood.Likelihood
class (see below).
Internal likelihoods are defined inside the likelihoods
directory of the Cobaya source tree, where each subdirectory defines
a subpackage containing one or more likelihoods. External likelihood classes can be defined in an external python package.
In addition to the likelihood class itself, each likelihood can have additional files:
a
[ClassName].yaml
file containing allowed options for each likelihood and the default experimental model:# Default options [option 1]: [value 1] [...] # Experimental model parameters params: [param 1]: prior: [prior info] [label, ref, etc.] prior: [prior 1]: [definition]
The options and parameters defined in this file are the only ones recognized by the likelihood, and they are loaded automatically with their default values (options) and priors (parameters) by simply mentioning the likelihood in the input file, where one can re-define any of those options with a different prior, value, etc (see Changing and redefining parameters; inheritance). The same parameter may be defined by different likelihoods; in those cases, it needs to have the same default information (prior, label, etc.) in the defaults file of all the likelihoods using it.
An optional
[ClassName].bibtex
file containing bibtex references associated with each likelihood, if relevant. Inherited likelihoods can be used to share a common .bibtex file, since the bibtex file is use by all descendants unless overridden.
Note
Likelihood class options are inherited from any ancestor class .yaml files or class attributes.
So there are some user-defined options that are common to all likelihoods and do not need to be specified in the defaults [ClassName].yaml
file, such as the computational speed
of the likelihood (see Taking advantage of a speed hierarchy).
It is up to you where to define your likelihood class(es): the __init__
file can define a class [ClassName] directly, or you can define a class in a module.py
file inside the likelihood directory (subpackage).
Using an internal likelihood class
Assuming your __init__
file defines the class, or imports it (from .module_name import ClassName
), when running Cobaya you can reference the internal likelihood using:
likelihood: directory_name.ClassName: [option 1]: [value 1] [...]
If you defined the class in module_name.py then you would reference it as
likelihood: directory_name.module_name.ClassName: [option 1]: [value 1] [...]
If the class name is the same as the module name it can be omitted.
Custom names and multiple instances of the same internal class
To rename an internal likelihood to your liking, or to use simultaneously several instances of the same internal likelihood class (e.g. with different options), give each instance a name of your choice and specify the original likelihood name using the class
keyword:
likelihood: my_like_1: class: directory_name.ClassName [option 1]: [value 1] [...] my_like_2: class: directory_name.ClassName [option 1]: [value 1] [...]
Using an external likelihood class
If you have a package called mycodes, containing a likelihood class called MyLike in mycodes.mylikes, when running Cobaya you can use the input
likelihood: mycodes.mylikes.MyLike: [option 1]: [value 1] [...]
This is assuming that mycodes is on your Python path (e.g. it is an installed package). You can also specify an explicit path for the module, e.g.
likelihood: mycodes.mylikes.MyLike: python_path: /path/to/mycodes_dir [option 1]: [value 1] [...]
If MyLike is imported by your package __init__
you can also simply reference it as mycodes.MyLike
.
Implementing your own likelihood class
For your likelihood class you just need to define a few standard class methods:
A
logp()
method taking a dictionary of (sampled) parameter values and returning a log-likelihood.An (optional)
initialize()
method preparing any computation, importing any necessary code, etc.An (optional)
get_requirements()
method returning dictionary of requests from a theory code component, if needed.
The latter two methods are standard for all Likelihood and Theory components, and are inherited from the base Theory
class.
There are also a number of other methods that you can also implement for more advanced usage.
Options defined in the [ClassName].yaml
are automatically accessible as attributes of your likelihood class at runtime, with values that can be overridden by the
input .yaml file used for the run. If you prefer you can also define class attributes directly, rather than using a .yaml file
(private class attributes that cannot be changed by input parameters should start with an underscore). If you define parameters in the .yaml you may also want to define
their type in the Python source by adding an annotation, which will make it easier to perform automated checks on your code.
For an example class implementation and how to support data file auto-installation, check out Creating your own cosmological likelihood class. There is also a simple external likelihood package and a real-word cosmology example in the sample external CMB likelihood. You could also use the Gaussian mixtures likelihood as a guide.
A likelihood package becomes an internal likelihood if you move it into Cobaya’s likelihoods
directory, but usually this is not necessary.
Keeping your likelihood in a separate packages makes it easier to separately update the codes , and you can their easily publicly distribute your likelihood package
(just having Cobaya as a package requirement).
If your likelihood depends on the calculation of some specific observable (typically depending on input parameters), you may want to split the calculation of the observable
into a separate Theory
class. This would allow different likelihoods to share the same theory calculation result, and also allow speed optimization if computing the likelihood
is much faster than calculating the observables that it depends on.
To understand how to make your own Theory and Likelihood classes, and handle dependencies between then, see Creating theory classes and dependencies.
Likelihood module
- Synopsis:
Likelihood class and likelihood collection
- Author:
Jesus Torrado and Antony Lewis
This module defines the main Likelihood
class, from which every likelihood
usually inherits, and the LikelihoodCollection
class, which groups and manages
all the individual likelihoods.
Likelihoods inherit from Theory
, adding an additional method
to return the likelihood. As with all theories, likelihoods cache results, and the
property LikelihoodInterface.current_logp()
is used by model.Model
to
calculate the total likelihood. The default Likelihood implementation does the actual
calculation of the log likelihood in the logp function, which is then called
by Likelihood.calculate()
to save the result into the current state.
Subclasses typically just provide the logp function to define their likelihood result,
and use get_requirements()
to specify which inputs are needed from
other theory codes (or likelihoods). Other methods of the Theory
base
class can be used as and when needed.
Likelihood class
- class likelihood.Likelihood(info=mappingproxy({}), name=None, timing=None, packages_path=None, initialize=True, standalone=True)
Base class for likelihoods. Extends from
LikelihoodInterface
and the generalTheory
class by adding functions to return likelihoods functions (logp function for a given point).- logp(**params_values)
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.
- marginal(directions=None, params_values=None)
(For analytic likelihoods only.) Computes the marginal likelihood. If nothing is specified, returns the total marginal likelihood. If some directions are specified (as a list, tuple or array), returns the marginal likelihood pdf over those directions evaluated at the given parameter values.
- calculate(state, want_derived=True, **params_values_dict)
Calculates the likelihood and any derived parameters or needs. Return False is the calculation fails.
Likelihood interface
- class likelihood.LikelihoodInterface
Interface function for likelihoods. Can descend from a
Theory
class and this to make a likelihood (where the calculate() method stores state[‘logp’] for the current parameters), or likelihoods can directly inherit fromLikelihood
instead.The current_logp property returns the current state’s logp as a scalar, and does not normally need to be changed.
- property current_logp: float
Gets log likelihood for the current point.
- Returns:
log likelihood from the current state as a scalar
LikelihoodCollection class
- class likelihood.LikelihoodCollection(info_likelihood, packages_path=None, timing=None, theory=None)
Bases:
ComponentCollection
A dictionary storing experimental likelihood
Likelihood
instances index by their names.