Source code for autofit.mapper.prior.uniform

from autofit.jax_wrapper import register_pytree_node_class
from typing import Optional

from autofit.messages.normal import UniformNormalMessage
from .abstract import Prior
from .abstract import epsilon
from ...messages.composed_transform import TransformedMessage
from ...messages.transform import LinearShiftTransform


[docs] @register_pytree_node_class class UniformPrior(Prior): __identifier_fields__ = ("lower_limit", "upper_limit") def __init__( self, lower_limit: float = 0.0, upper_limit: float = 1.0, id_: Optional[int] = None, ): """ A prior with a uniform distribution, defined between a lower limit and upper limit. The conversion of an input unit value, ``u``, to a physical value, ``p``, via the prior is as follows: .. math:: For example for ``prior = UniformPrior(lower_limit=0.0, upper_limit=2.0)``, an input ``prior.value_for(unit=0.5)`` is equal to 1.0. [Rich describe how this is done via message] Parameters ---------- lower_limit The lower limit of the uniform distribution defining the prior. upper_limit The upper limit of the uniform distribution defining the prior. Examples -------- prior = af.UniformPrior(lower_limit=0.0, upper_limit=2.0) physical_value = prior.value_for(unit=0.2) """ lower_limit = float(lower_limit) upper_limit = float(upper_limit) message = TransformedMessage( UniformNormalMessage, LinearShiftTransform(shift=lower_limit, scale=upper_limit - lower_limit), lower_limit=lower_limit, upper_limit=upper_limit, ) super().__init__( message, lower_limit=lower_limit, upper_limit=upper_limit, id_=id_, ) def tree_flatten(self): return (self.lower_limit, self.upper_limit), (self.id,)
[docs] def with_limits( self, lower_limit: float, upper_limit: float, ) -> "Prior": return UniformPrior( lower_limit=lower_limit, upper_limit=upper_limit, )
def logpdf(self, x): # TODO: handle x as a numpy array if x == self.lower_limit: x += epsilon elif x == self.upper_limit: x -= epsilon return self.message.logpdf(x) @property def parameter_string(self) -> str: return f"lower_limit = {self.lower_limit}, upper_limit = {self.upper_limit}"
[docs] def value_for(self, unit: float, ignore_prior_limits: bool = False) -> float: """ Returns a physical value from an input unit value according to the limits of the uniform prior. Parameters ---------- unit A unit value between 0 and 1. Returns ------- value The unit value mapped to a physical value according to the prior. Examples -------- prior = af.UniformPrior(lower_limit=0.0, upper_limit=2.0) physical_value = prior.value_for(unit=0.2) """ return float( round(super().value_for(unit, ignore_prior_limits=ignore_prior_limits), 14) )
[docs] def log_prior_from_value(self, value): """ Returns the log prior of a physical value, so the log likelihood of a model evaluation can be converted to a posterior as log_prior + log_likelihood. This is used by certain non-linear searches (e.g. Emcee) in the log likelihood function evaluation. For a UniformPrior this is always zero, provided the value is between the lower and upper limit. """ return 0.0