Source code for infobs.sampling.samplers

from abc import ABC, abstractmethod
from typing import Optional

import numpy as np

__all__ = ["Sampler", "Constant", "Uniform", "LogUniform", "BoundedPowerLaw"]


[docs] class Sampler(ABC): """abstract sampler class"""
[docs] @abstractmethod def get(self, n: int) -> np.ndarray: """samples from the considered sampler Parameters ---------- n : int number of samples to draw Returns ------- np.ndarray of shape (n,) sampled physical parameter values """ pass
[docs] class Constant(Sampler): """simplest possible probability distribution: a Dirac at a given value""" def __init__(self, value: float): """ Parameters ---------- value : float considered constant value for the physical parameter """ self.value = value
[docs] def get(self, n: int) -> np.ndarray: return self.value * np.ones(n, dtype=float)
[docs] def copy_other_bounds(self, value: float): return Constant(value)
def __str__(self): return f"Constant(value={self.value})"
[docs] class Uniform(Sampler): """uniform distribution on a possible open-ended interval""" def __init__(self, lower: float, upper: Optional[float] = None): """ Parameters ---------- lower : float lower bound of the uniform distribution upper : Optional[float], optional upper bound of the uniform distribution, by default None """ assert upper is None or upper >= lower self.lower = lower self.upper = upper or lower
[docs] def get(self, n: int) -> np.ndarray: return np.random.uniform(self.lower, self.upper, n)
[docs] def copy_other_bounds(self, lower: float, upper: Optional[float] = None): return Uniform(lower, upper)
def __str__(self): return f"Uniform(lower={self.lower}, upper={self.upper})"
[docs] class LogUniform(Sampler): """log-uniform distribution on a possible open-ended interval""" def __init__(self, lower: float, upper: Optional[float] = None, base: float = 10.0): """ Parameters ---------- lower : float lower bound of the log-uniform distribution upper : Optional[float], optional upper bound of the log-uniform distribution, by default None base : float, optional logarithm base, by default 10. """ assert lower > 0 assert upper is None or upper >= lower assert base > 1 self.lower = lower self.upper = upper or lower self.base = base
[docs] def get(self, n: int) -> np.ndarray: a = np.log(self.lower) / np.log(self.base) b = np.log(self.upper) / np.log(self.base) return self.base ** np.random.uniform(a, b, n)
[docs] def copy_other_bounds(self, lower: float, upper: Optional[float] = None): return LogUniform(lower, upper, base=self.base)
def __str__(self): return f"LogUniform(lower={self.lower}, upper={self.upper}, base={self.base})"
[docs] class BoundedPowerLaw(Sampler): """bounded power law distribution on a possible open-ended interval""" def __init__(self, alpha: float, lower: float, upper: Optional[float] = None): """ Parameters ---------- alpha : float exponent value of the power law distribution lower : float lower bound of the bounded power law distribution upper : Optional[float], optional upper bound of the bounded power law distribution, by default None """ assert lower > 0 assert upper is None or upper >= lower self.alpha = alpha self.lower = lower self.upper = upper or lower
[docs] def get(self, n: int) -> np.ndarray: a = self.lower**self.alpha b = self.upper**self.alpha - a return (a + b * np.random.rand(n)) ** (1 / self.alpha)
[docs] def copy_other_bounds(self, lower: float, upper: Optional[float] = None): return BoundedPowerLaw(self.alpha, lower, upper)
def __str__(self): return f"BoundedPowerLaw(alpha={self.alpha}, lower={self.lower}, upper={self.upper})"