Source code for prior

"""
.. module:: prior
    :synopsis: Define the Prior class

.. moduleauthor:: Benjamin Audren <benjamin.audren@epfl.ch>
"""
import random as rd
from copy import deepcopy
import io_mp


[docs]class Prior(object): """ Store the type of prior associated to a parameter """ def __init__(self, array): """ It takes as an optional input argument the array of the input :data:`parameters` defined in the parameter file. The current implemented types are 'flat' (default), and 'gaussian', which expect also a mean and sigma. Possible extension would take a 'external', needing to read an external file to read for the definition. The entry 'prior' of the dictionary :data:`mcmc_parameters` will hold an instance of this class. It defines one main function, called :func:`draw_from_prior`, that returns a number within the prior volume. """ rd.seed() # Test the length of the array, and initialize the type. if len(array) == 6: # Default behaviour, flat prior self.prior_type = 'flat' else: self.prior_type = array[6].lower() # in case of a gaussian prior, one expects two more entries, mu and # sigma if self.prior_type == 'gaussian': try: self.mu = array[7] self.sigma = array[8] except IndexError: raise io_mp.ConfigurationError( "You asked for a gaussian prior, but provided no " + "mean nor sigma. Please add them in the parameter " + "file.") # Store boundaries for convenient access later # Put all fields that are -1 to None to avoid confusion later on. self.prior_range = [a if not((a is -1) or (a is None)) else None for a in deepcopy(array[1:3])]
[docs] def draw_from_prior(self): """ Draw a random point from the prior range considering the prior type Returns ------- value : float A random sample inside the prior region """ if self.prior_type == 'flat': return rd.uniform(self.prior_range[0], self.prior_range[1]) elif self.prior_type == 'gaussian': within_bounds = False while not within_bounds: value = rd.gauss(self.mu, self.sigma) # Check for boundaries problem within_bounds = calue_within_prior_range(value) return value
[docs] def value_within_prior_range(self, value): """ Check for a value being in or outside the prior range """ flag = 0 if (self.prior_range[0] is not None and value < self.prior_range[0]): flag += 1 elif (self.prior_range[1] is not None and value > self.prior_range[1]): flag += 1 if flag > 0: return False else: return True
[docs] def is_bound(self): """ Checks whether the allowed parameter range is finite """ return (self.prior_range[0] is not None and self.prior_range[1] is not None)
[docs] def map_from_unit_interval(self, value): """ Linearly maps a value of the interval [0,1] to the parameter range. For the sake of speed, assumes the parameter to be bound to a finite range, \ which should have been previously checked with :func:`is_bound` """ return (self.prior_range[0] + value * (self.prior_range[1] - self.prior_range[0]))