Source code for taurex.core.priors

"""Handles how priors are defined for retrievals."""
import enum
import math
import typing as t

import scipy.stats as stats

from taurex.log import Logger


[docs] class PriorMode(enum.Enum): """Defines the type of prior space.""" LINEAR = 0 LOG = 1
[docs] class Prior(Logger): """Defines a prior function""" def __init__(self) -> None: """Initialise prior""" super().__init__(self.__class__.__name__) self._prior_mode = PriorMode.LINEAR @property def priorMode(self) -> PriorMode: # noqa: N802 """Defined prior mode.""" return self._prior_mode
[docs] def sample(self, x: float) -> float: """Sample the prior. Parameters ---------- x : float A random number between 0 and 1. Raises ------ NotImplementedError [description] """ raise NotImplementedError
[docs] def prior(self, value: float) -> float: """Convert a value from prior space to linear space.""" if self._prior_mode is PriorMode.LINEAR: return value else: return 10**value
[docs] def params(self) -> str: """Return the parameters of the prior in string form. Raises: NotImplementedError: [description] """ raise NotImplementedError
[docs] def boundaries(self) -> t.Tuple[float, float]: """Return the (rough) boundaries of the prior. Raises: NotImplementedError: [description] """ raise NotImplementedError
[docs] class Uniform(Prior): """Defines a uniform prior.""" def __init__( self, bounds: t.Optional[t.Tuple[float, float]] = ( 0.0, 1.0, ), ): """Initialise uniform prior. Parameters ---------- bounds : tuple, optional Bounds of the prior, by default (0.0, 1.0) Raises ------ ValueError If no bounds are defined. """ super().__init__() if bounds is None: self.error("No bounds defined") raise ValueError("No bounds defined") self.set_bounds(bounds)
[docs] def set_bounds(self, bounds: t.Tuple[float, float]): """Set the bounds of the prior. Parameters ---------- bounds : t.Tuple[float, float] Bounds of the prior. """ self._low_bounds = min(*bounds) self.debug("Lower bounds: %s", self._low_bounds) self._up_bounds = max(*bounds) self._scale = self._up_bounds - self._low_bounds self.debug("Scale: %s", self._scale)
[docs] def sample(self, x: float) -> float: """Sample the prior. Parameters ---------- x : float A random number between 0 and 1. """ return stats.uniform.ppf(x, loc=self._low_bounds, scale=self._scale)
[docs] def params(self): """Return the parameters of the prior in string form. Returns ------- str String representation of the prior. """ return f"Bounds = [{self._low_bounds},{self._up_bounds}]"
[docs] def boundaries(self) -> t.Tuple[float, float]: """Return the boundaries of the prior.""" return self._low_bounds, self._up_bounds
[docs] class LogUniform(Uniform): """Defines a log-uniform prior.""" def __init__( self, bounds: t.Optional[t.Tuple[float, float]] = ( 0.0, 1.0, ), lin_bounds=None, ): """Initialise log-uniform prior. Parameters ---------- bounds : list, optional Bounds of the prior in logspace, by default [0.0, 1.0] lin_bounds : list, optional Bounds of the prior in linear space, by default None """ if lin_bounds is not None: bounds = [math.log10(x) for x in lin_bounds] super().__init__(bounds=bounds) self._prior_mode = PriorMode.LOG
[docs] class Gaussian(Prior): """Defines a gaussian prior.""" def __init__(self, mean: t.Optional[float] = 0.5, std: t.Optional[float] = 0.25): """Initialise gaussian prior. Parameters ---------- mean : float, optional Mean of the gaussian, by default 0.5 std : float, optional Standard deviation of the gaussian, by default 0.25 """ super().__init__() self._loc = mean self._scale = std
[docs] def sample(self, x: float) -> float: """Sample the prior. Parameters ---------- x : float A random number between 0 and 1. """ return stats.norm.ppf(x, loc=self._loc, scale=self._scale)
[docs] def params(self) -> str: """Return the parameters of the prior in string form.""" return f"Mean = {self._loc} Stdev = {self._scale}"
[docs] def boundaries(self) -> t.Tuple[float, float]: """Return the boundaries of the prior.""" return self.sample(0.1), self.sample(0.9)
[docs] class LogGaussian(Gaussian): """Defines a log-gaussian prior.""" def __init__( self, mean: t.Optional[float] = 0.5, std: t.Optional[float] = 0.25, lin_mean: t.Optional[float] = None, lin_std: t.Optional[float] = None, ): """Initialise log-gaussian prior. Parameters ---------- mean : float, optional Mean of the gaussian, by default 0.5 std : float, optional Standard deviation of the gaussian, by default 0.25 lin_mean : float, optional Mean of the gaussian in linear space, by default None lin_std : float, optional Standard deviation of the gaussian in linear space, by default None """ if lin_mean is not None: mean = math.log10(lin_mean) if lin_std is not None: std = math.log10(lin_std) super().__init__(mean=mean, std=std) self._prior_mode = PriorMode.LOG