Source code for gemseo.uncertainty.distributions.scipy.distribution

# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program 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 this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# Contributors:
#    INITIAL AUTHORS - initial API and implementation and/or initial
#                           documentation
#        :author: Matthias De Lozzo
#    OTHER AUTHORS   - MACROSCOPIC CHANGES
"""The interface to SciPy-based probability distributions."""

from __future__ import annotations

from typing import TYPE_CHECKING
from typing import ClassVar

import scipy.stats as scipy_stats
from scipy.stats._distn_infrastructure import rv_continuous_frozen

from gemseo.typing import StrKeyMapping
from gemseo.uncertainty.distributions.base_distribution import BaseDistribution
from gemseo.uncertainty.distributions.scalar_distribution_mixin import (
    ScalarDistributionMixin,
)
from gemseo.uncertainty.distributions.scipy.joint import SPJointDistribution
from gemseo.utils.constants import READ_ONLY_EMPTY_DICT

if TYPE_CHECKING:
    from collections.abc import Generator

    from numpy.random import RandomState

    from gemseo.typing import RealArray
    from gemseo.uncertainty.distributions.base_distribution import (
        StandardParametersType,
    )
    from gemseo.uncertainty.distributions.base_joint import BaseJointDistribution


[docs] class SPDistribution( BaseDistribution[float, StrKeyMapping, rv_continuous_frozen], ScalarDistributionMixin, ): """A SciPy-based probability distribution. .. warning:: The distribution parameters must be provided according to the signature of the scipy classes. `Access the scipy documentation <https://docs.scipy.org/doc/scipy/reference/stats.html>`_. Examples: >>> from gemseo.uncertainty.distributions.scipy.distribution import ( ... SPDistribution, ... ) >>> distribution = SPDistribution("expon", {"loc": 3, "scale": 1 / 2.0}) >>> print(distribution) expon(loc=3, scale=0.5) """ JOINT_DISTRIBUTION_CLASS: ClassVar[type[BaseJointDistribution]] = ( SPJointDistribution ) _WEBSITE: ClassVar[str] = "https://docs.scipy.org/doc/scipy/reference/stats.html" def __init__( # noqa: D107 self, interfaced_distribution: str = "uniform", parameters: StrKeyMapping = READ_ONLY_EMPTY_DICT, standard_parameters: StandardParametersType = READ_ONLY_EMPTY_DICT, ) -> None: """ Args: standard_parameters: The parameters of the probability distribution used for string representation only (use ``parameters`` for computation). If empty, use ``parameters`` instead. For instance, let us consider the interfaced SciPy distribution ``"uniform"``. Then, the string representation of ``SPDistribution("uniform", parameters, 1, {"min": 1, "max": 3})`` with ``parameters={"loc": 1, "scale": 2}`` is ``"uniform(max=3, min=1)"`` while the string representation of ``SPDistribution("uniform", parameters)`` is ``"uniform(loc=1, scale=2)"``. """ # noqa: D205 D212 D415 super().__init__(interfaced_distribution, parameters, standard_parameters) def _create_distribution( self, distribution_name: str, parameters: StrKeyMapping, ) -> None: distribution = self._create_distribution_from_module( scipy_stats, distribution_name, parameters ) self.math_lower_bound, self.math_upper_bound = distribution.interval(1.0) extrema_level = 1e-12 self.num_lower_bound = distribution.ppf(extrema_level) self.num_upper_bound = distribution.ppf(1 - extrema_level) self.distribution = distribution
[docs] def compute_samples( # noqa: D102 self, n_samples: int = 1, random_state: None | int | Generator | RandomState = None, ) -> RealArray: """ Args: random_state: The SciPy random state. """ # noqa: D205, D212 return self.distribution.rvs(n_samples, random_state)
[docs] def compute_cdf( # noqa: D102 self, value: float, ) -> float: return self.distribution.cdf(value)
[docs] def compute_inverse_cdf( # noqa: D102 self, value: float, ) -> float: return self.distribution.ppf(value)
@property def mean(self) -> float: # noqa: D102 return self.distribution.mean() @property def standard_deviation(self) -> float: # noqa: D102 return self.distribution.std() def _pdf( self, value: float, ) -> float: return self.distribution.pdf(value) def _cdf( self, level: float, ) -> float: return self.distribution.cdf(level)