Source code for pyvbmc.priors.uniform_box

from textwrap import indent

import numpy as np

from pyvbmc.formatting import full_repr
from pyvbmc.priors import Prior, tile_inputs


[docs] class UniformBox(Prior): """Multivariate uniform-box prior. A prior distribution represented by box of uniform dimension, with lower bound(s) ``a`` and upper bound(s) ``b``. Attributes ---------- D : int The dimension of the prior distribution. a : np.ndarray The lower bound(s), shape `(1, D)`. b : np.ndarray The upper bound(s), shape `(1, D)`. """
[docs] def __init__(self, a, b, D=None): """Initialize a multivariate uniform-box prior. Parameters ---------- a : np.ndarray | float The lower bound(s), shape `(D,)` where `D` is the dimension (parameters of type ``float`` will be tiled to this shape). b : np.ndarray | float The upper bound(s), shape `(D,)` where `D` is the dimension (parameters of type ``float`` will be tiled to this shape). Raises ------ ValueError If ``a[i] >= b[i]``, for any `i`. """ self.a, self.b = tile_inputs(a, b, size=D, squeeze=True) if np.any(self.a >= self.b): raise ValueError( f"All elements of a={a} should be strictly less than b={b}." ) self.D = self.a.size
def _log_pdf(self, x): """Compute the log-pdf of the multivariate uniform-box prior. Parameters ---------- x : np.ndarray The array of input point(s), of dimension `(D,)` or `(n,D)`, where `D` is the distribution dimension. Returns ------- log_pdf : np.ndarray The log-density of the prior at the input point(s), of dimension `(n, 1)`. """ n, D = x.shape log_norm_factor = np.sum(np.log(self.b - self.a)) log_pdf = np.full((n, 1), -log_norm_factor) mask = np.any((x < self.a) | (x > self.b), axis=1) log_pdf[mask] = -np.inf return log_pdf def sample(self, n): """Sample random variables from the uniform-box distribution. Parameters ---------- n : int The number of points to sample. Returns ------- rvs : np.ndarray The samples points, of shape `(n, D)`, where `D` is the dimension. """ return np.random.uniform(self.a, self.b, size=(n, self.D)) @classmethod def _generic(cls, D=1): """Return a generic instance of the class (used for tests).""" return UniformBox( np.zeros(D), np.ones(D), ) def _support(self): """Returns the support of the distribution. Used to test that the distribution integrates to one, so it is also acceptable to return a box which bounds the support of the distribution. Returns ------- lb, ub : tuple(np.ndarray, np.ndarray) A tuple of lower and upper bounds of the support, such that [``lb[i]``, ``ub[i]``] bounds the support of the `i`th marginal. """ return self.a, self.b def __str__(self): """Print a string summary.""" return "UniformBox prior:" + indent( f""" dimension = {self.D}, lower bounds = {self.a}, upper bounds = {self.b}""", " ", ) def __repr__(self, arr_size_thresh=10, expand=False): """Construct a detailed string summary. Parameters ---------- arr_size_thresh : float, optional If ``obj`` is an array whose product of dimensions is less than ``arr_size_thresh``, print the full array. Otherwise print only the shape. Default `10`. expand : bool, optional If ``expand`` is `False`, then describe any complex child attributes of the object by their name and memory location. Otherwise, recursively expand the child attributes into their own representations. Default `False`. Returns ------- string : str The string representation of ``self``. """ return full_repr( self, "UniformBox", order=[ "D", "a", "b", ], expand=expand, arr_size_thresh=arr_size_thresh, )