Source code for queens.distributions.uniform

#
# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (c) 2024-2025, QUEENS contributors.
#
# This file is part of QUEENS.
#
# QUEENS is free software: you can redistribute it and/or modify it under the terms of the GNU
# Lesser General Public License as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version. QUEENS is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You
# should have received a copy of the GNU Lesser General Public License along with QUEENS. If not,
# see <https://www.gnu.org/licenses/>.
#
"""Uniform distribution."""

import numpy as np
import scipy.stats
from numpy.typing import ArrayLike

from queens.distributions._distribution import Continuous
from queens.utils.logger_settings import log_init_args


[docs] class Uniform(Continuous): """Uniform distribution class. Attributes: lower_bound: Lower bound(s) of the distribution. upper_bound: Upper bound(s) of the distribution. width: Width(s) of the distribution. pdf_const: Constant for the evaluation of the PDF. logpdf_const: Constant for the evaluation of the log-PDF. """ @log_init_args def __init__(self, lower_bound: ArrayLike, upper_bound: ArrayLike) -> None: """Initialize uniform distribution. Args: lower_bound: Lower bound(s) of the distribution upper_bound: Upper bound(s) of the distribution """ lower_bound = np.array(lower_bound).reshape(-1) upper_bound = np.array(upper_bound).reshape(-1) super().check_bounds(lower_bound, upper_bound) width = upper_bound - lower_bound mean = (lower_bound + upper_bound) / 2.0 covariance = np.diag(width**2 / 12.0) dimension = mean.size pdf_const = 1.0 / np.prod(width) logpdf_const = np.log(pdf_const) super().__init__(mean=mean, covariance=covariance, dimension=dimension) self.lower_bound = lower_bound self.upper_bound = upper_bound self.width = width self.pdf_const = pdf_const self.logpdf_const = logpdf_const
[docs] def cdf(self, x: np.ndarray) -> np.ndarray: """Cumulative distribution function. Args: x: Positions at which the CDF is evaluated Returns: CDF at positions """ cdf = np.prod( np.clip( (x.reshape(-1, self.dimension) - self.lower_bound) / self.width, a_min=np.zeros(self.dimension), a_max=np.ones(self.dimension), ), axis=1, ) return cdf
[docs] def draw(self, num_draws: int = 1) -> np.ndarray: """Draw samples. Args: num_draws: Number of draws Returns: Drawn samples from the distribution """ samples = np.random.uniform( low=self.lower_bound, high=self.upper_bound, size=(num_draws, self.dimension) ) return samples
[docs] def logpdf(self, x: np.ndarray) -> np.ndarray: """Log of the probability density function. Args: x: Positions at which the log-PDF is evaluated Returns: Log-PDF at positions """ x = x.reshape(-1, self.dimension) within_bounds = (x >= self.lower_bound).all(axis=1) * (x <= self.upper_bound).all(axis=1) logpdf = np.where(within_bounds, self.logpdf_const, -np.inf) return logpdf
[docs] def grad_logpdf(self, x: np.ndarray) -> np.ndarray: """Gradient of the log-PDF with respect to *x*. Args: x: Positions at which the gradient of log-PDF is evaluated Returns: Gradient of the log-PDF evaluated at positions """ x = x.reshape(-1, self.dimension) grad_logpdf = np.zeros(x.shape) return grad_logpdf
[docs] def pdf(self, x: np.ndarray) -> np.ndarray: """Probability density function. Args: x: Positions at which the PDF is evaluated Returns: PDF at positions """ x = x.reshape(-1, self.dimension) # Check if positions are within bounds of the uniform distribution within_bounds = (x >= self.lower_bound).all(axis=1) * (x <= self.upper_bound).all(axis=1) pdf = within_bounds * self.pdf_const return pdf
[docs] def ppf(self, quantiles: np.ndarray) -> np.ndarray: """Percent point function (inverse of cdf — quantiles). Args: quantiles: Quantiles at which the PPF is evaluated Returns: Positions which correspond to given quantiles """ self.check_1d() ppf = scipy.stats.uniform.ppf(q=quantiles, loc=self.lower_bound, scale=self.width).reshape( -1 ) return ppf