Source code for cuqi.legacy.sampler._conjugate
from cuqi.distribution import Posterior, Gaussian, Gamma, GMRF
from cuqi.implicitprior import RegularizedGaussian, RegularizedGMRF
import numpy as np
[docs]
class Conjugate: # TODO: Subclass from Sampler once updated
""" Conjugate sampler
Sampler for sampling a posterior distribution where the likelihood and prior are conjugate.
Currently supported conjugate pairs are:
- (Gaussian, Gamma)
- (GMRF, Gamma)
- (RegularizedGaussian, Gamma) with nonnegativity constraints only
For more information on conjugate pairs, see https://en.wikipedia.org/wiki/Conjugate_prior.
For implicit regularized Gaussians see:
[1] Everink, Jasper M., Yiqiu Dong, and Martin S. Andersen. "Bayesian inference with projected densities." SIAM/ASA Journal on Uncertainty Quantification 11.3 (2023): 1025-1043.
"""
[docs]
def __init__(self, target: Posterior):
if not isinstance(target.likelihood.distribution, (Gaussian, GMRF, RegularizedGaussian, RegularizedGMRF)):
raise ValueError("Conjugate sampler only works with a Gaussian-type likelihood function")
if not isinstance(target.prior, Gamma):
raise ValueError("Conjugate sampler only works with Gamma prior")
if not target.prior.dim == 1:
raise ValueError("Conjugate sampler only works with univariate Gamma prior")
if isinstance(target.likelihood.distribution, (RegularizedGaussian, RegularizedGMRF)) and (target.likelihood.distribution.preset["constraint"] not in ["nonnegativity"] or target.likelihood.distribution.preset["regularization"] is not None) :
raise ValueError("Conjugate sampler only works implicit regularized Gaussian likelihood with nonnegativity constraints")
self.target = target
[docs]
def step(self, x=None):
# Extract variables
b = self.target.likelihood.data #mu
m = self._calc_m_for_Gaussians(b) #n
Ax = self.target.likelihood.distribution.mean #x_i
L = self.target.likelihood.distribution(np.array([1])).sqrtprec #L
alpha = self.target.prior.shape #alpha
beta = self.target.prior.rate #beta
# Create Gamma distribution and sample
dist = Gamma(shape=m/2+alpha,rate=.5*np.linalg.norm(L@(Ax-b))**2+beta)
return dist.sample()
def _calc_m_for_Gaussians(self, b):
""" Helper method to calculate m parameter for Gaussian-Gamma conjugate pair. """
if isinstance(self.target.likelihood.distribution, (Gaussian, GMRF)):
return len(b)
elif isinstance(self.target.likelihood.distribution, (RegularizedGaussian, RegularizedGMRF)):
return np.count_nonzero(b) # See