Source code for binf.pdf

"""
This module provides general functionality and classes
related to probability density functions and their parameters.
"""

from abc import ABCMeta, abstractmethod

from binf import AbstractBinfNamedCallable

from csb.numeric import exp
from csb.statistics.pdf.parameterized import ParameterizedDensity


[docs]class ParameterNotFoundError(AttributeError): pass
[docs]class AbstractBinfPDF(ParameterizedDensity, AbstractBinfNamedCallable): __metaclass__ = ABCMeta def __init__(self, name='', **args): r""" Defines the interface for probability density functions, combining the CSB PDF classes with the interface for functions taking typed and named variables :param name: name for this object :type name: str :param \**args: arguments required for instantiation """ ParameterizedDensity.__init__(self) AbstractBinfNamedCallable.__init__(self, name) self._var_param_types = {} @property def estimator(self): raise NotImplementedError @estimator.setter def estimator(self, strategy): pass
[docs] def estimate(self, data): raise NotImplementedError
[docs] def conditional_factory(self, **fixed_vars): r""" Makes a copy of this object in which one or several variables are set to specific values (on which the new PDF is 'conditioned' on) The 'conditioning' must not be taken literally, as no prior probabilities are taken into account. But that doesn't bother us, as we're going to MCMC sampling anyways :param \**variables: keyword arguments containg name / value pairs for variables on which this PDF should be conditioned on :returns: PDF object conditioned on the given values :rtype: :class:`.AbstractBinfPDF` """ result = self.clone() result.fix_variables(**self._get_variables_intersection(fixed_vars)) return result
[docs] @abstractmethod def _evaluate_log_prob(self, **variables): r""" In this method, the actual evaluation of the log-probability takes place The variables argument holds values for both fixed and unfixed variables; the implementation in this method thus does not depend on whether the set of originally passed variables equals the set of original variables :param \**variables: list of variable name / value pairs """ pass
[docs] def _evaluate(self, **variables): return exp(self.log_prob(**variables))
[docs] def log_prob(self, **variables): r""" Evaluates the log-probability of the PDF represented by this object :param \**variables: list of variable name / value pairs :returns: log-probability :rtype: float """ self._complete_variables(variables) result = self._evaluate_log_prob(**variables) return result
[docs] def gradient(self, **variables): self._complete_variables(variables) result = self._evaluate_gradient(**variables) return result
[docs] def fix_variables(self, **fixed_vars): """ Sets ('fixes') specific variables to values given as keyword arguments by removing these variables from the list of registered variables and registering corresponding parameters to this object. """ for v in fixed_vars: if v in self.variables: self._delete_variable(v) self._register(v) if v in self.var_param_types: self[v] = self.var_param_types[v](fixed_vars[v], v) else: msg = 'Parameter type for variable "{}" not defined'.format(v) raise ValueError(msg) else: msg = '{} is not a variable of {}'.format(self.__repr__(), v) raise ValueError(msg)
[docs] @abstractmethod def clone(self): """ Returns an exact copy (same parameters / variables...) of this object :returns: a copy of this object :rtype: :class:`.AbstractBinfPDF` """ pass
[docs] def set_fixed_variables_from_pdf(self, pdf): """ Retrieves fixed variables from another PDF object and fixes the same variables in this object accordingly :param pdf: PDF object to retrieve variables to fix from :type pdf: :class:`.AbstractBinfPDF` """ variables = {p: pdf[p].value for p in pdf.parameters if not p in self.parameters} self.fix_variables(**self._get_variables_intersection(variables))
[docs] def _complete_variables(self, variables): ''' _complete_variables and _reduce_variables so far only work for classes which both inherit from AbstractBinfNamedCallable and can hold parameters (that is, PDFs and models) ''' variables.update(**{p: self[p].value for p in self.parameters if p in self._original_variables})
[docs]class TestHO(AbstractBinfPDF): def __init__(self, k=1.0, x0=0.0, name='TestHO'): from csb.statistics.pdf.parameterized import Parameter from hicbinf.hicbinflib import ArrayParameter super(TestHO, self).__init__(name=name) self._register('k') self._register('x0') self['k'] = Parameter(k, name='k') self['x0'] = Parameter(x0, name='x0') self._register_variable('x', differentiable=True) self._set_original_variables() self.update_var_param_types(x=ArrayParameter)
[docs] def _evaluate_log_prob(self, x): import numpy return -0.5 * self['k'].value * numpy.sum((x - self['x0'].value) ** 2)
[docs] def _evaluate_gradient(self, x): import numpy return self['k'].value * (x - self['x0'].value)