Source code for cuqi.distribution._beta
import numpy as np
import scipy.stats as sps
from cuqi.geometry import _get_identity_geometries
from cuqi.utilities import force_ndarray
from cuqi.distribution import Distribution
[docs]
class Beta(Distribution):
"""
Multivariate beta distribution of independent random variables x_i. Each is distributed according to the PDF function
.. math::
f(x) = x^{(\\alpha-1)}(1-x)^{(\\beta-1)}\Gamma(\\alpha+\\beta) / (\Gamma(\\alpha)\Gamma(\\beta))
where :math:`\Gamma` is the Gamma function.
Parameters
------------
alpha: float or array_like
The shape parameter :math:`\\alpha` of the beta distribution.
beta: float or array_like
The shape parameter :math:`\\beta` of the beta distribution.
Example
-------
.. code-block:: python
# % Generate a beta distribution
import numpy as np
import cuqi
import matplotlib.pyplot as plt
alpha = 0.5
beta = 0.5
rng = np.random.RandomState(1)
x = cuqi.distribution.Beta(alpha, beta)
samples = x.sample(1000, rng=rng)
samples.hist_chain(0, bins=70)
"""
[docs]
def __init__(self, alpha=None, beta=None, is_symmetric=False, **kwargs):
super().__init__(is_symmetric=is_symmetric, **kwargs)
self.alpha = force_ndarray(alpha, flatten=True)
self.beta = force_ndarray(beta, flatten=True)
[docs]
def logpdf(self, x):
# Check bounds
if np.any(x<=0) or np.any(x>=1) or np.any(self.alpha<=0) or np.any(self.beta<=0):
return -np.inf
# Compute logpdf
return np.sum(sps.beta.logpdf(x, a=self.alpha, b=self.beta))
[docs]
def cdf(self, x):
# Check bounds
if np.any(x<=0) or np.any(x>=1) or np.any(self.alpha<=0) or np.any(self.beta<=0):
return 0
# Compute logpdf
return np.prod(sps.beta.cdf(x, a=self.alpha, b=self.beta))
def _sample(self, N=1, rng=None):
return sps.beta.rvs(a=self.alpha, b=self.beta, size=(N,self.dim), random_state=rng).T
def _gradient(self, x, *args, **kwargs):
#Avoid complicated geometries that change the gradient.
if not type(self.geometry) in _get_identity_geometries():
raise NotImplementedError("Gradient not implemented for distribution {} with geometry {}".format(self,self.geometry))
#Computing the gradient for conditional InverseGamma distribution is not supported yet
if self.is_cond:
raise NotImplementedError(f"Gradient is not implemented for {self} with conditioning variables {self.get_conditioning_variables()}")
# Check bounds (return nan if out of bounds)
if np.any(x<=0) or np.any(x>=1) or np.any(self.alpha<=0) or np.any(self.beta<=0):
return x*np.nan
#Compute the gradient
return (self.alpha - 1)/x + (self.beta-1)/(x-1)