Source code for cosapp.utils.distributions.distribution

"""Basic class to define a variable distribution."""
from abc import ABC, abstractmethod
from typing import Any, Optional


EPS = 1e-12


[docs] class Distribution(ABC): """Abstract class to define a variable distribution. Parameters ---------- worst : float The parameter absolute worst value. best : float The parameter absolute best value. pworst : float, optional The worst value probability is the probability that the variable will be lower (if worst<best) or higher (if worst>best) than the worst value; default 0.15 (i.e. 15%). pbest : float, optional The best value probability is the probability that the variable will be higher (if worst<best) or lower (if worst>best) than the best value; default 0.15 (i.e. 15%). """ # TODO should we forbid worst > best __slots__ = ("__weakref__", "_best", "_pbest", "_pworst", "_worst") def __init__( self, worst: float, best: float, pworst: Optional[float] = 0.15, pbest: Optional[float] = 0.15, ): self._worst = worst self._best = best # Need to initiate with EPS to be sure to fulfill pworst + pbest < 1. # We don't initialise to 0. otherwise fitting distribution for unbounded # one will fail (like the normal distribution) self._pworst = EPS self._pbest = EPS self.pworst = pworst self.pbest = pbest def __json__(self) -> dict[str, Any]: """Creates a JSONable dictionary representation of the object. Returns ------- dict[str, Any] The dictionary """ return { "worst": self.worst, "pworst": self.pworst, "best": self.best, "pbest": self.pbest, } @abstractmethod def _set_distribution(self) -> None: """Set the probability distribution according the parameters.""" pass @property def worst(self) -> float: """float: The worst possible value of the variable. It is defined as an absolute value. It has a physical meaning, i.e. it can be numerically higher than the best value. The probability to meet the worst value is given by the `pworst` property. """ return self._worst @worst.setter def worst(self, value): self._worst = value self._set_distribution() @property def pworst(self) -> float: """float: The worst value probability. It is the probability that the variable will be lower (if worst<best) or higher (if worst>best) than the worst value. """ return self._pworst @pworst.setter def pworst(self, value: float): if not (0.0 <= value <= 1.0): raise ValueError( f"Worst probability does not verify 0 <= {value} <= 1." ) self._pworst = value self._set_distribution() @property def best(self) -> float: """float : The best possible value of the variable. It is defined as an absolute value. It has a physical meaning, i.e. it can be numerically lower than the worst value. The probability to meet the best value is given by the `pbest` property. """ return self._best @best.setter def best(self, value: float): self._best = value self._set_distribution() @property def pbest(self) -> float: """float: The best value probability. It is the probability that the variable will be higher (if worst<best) or lower (if worst>best) than the best value. """ return self._pbest @pbest.setter def pbest(self, value: float): if not (0.0 <= value <= 1.0): raise ValueError( f"Best probability does not verify 0 <= {value} <= 1." ) self._pbest = value self._set_distribution()
[docs] @abstractmethod def draw(self, quantile: Optional[float]=None) -> float: """Generate a random number. If a quantile is given, generate the perturbation for that quantile. Parameters ---------- quantile : Optional[float], optional Quantile for which the perturbation must be set; default None (i.e. random perturbation) Returns ------- float The random number """ pass