# 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 API for uncertainty quantification and management."""
from __future__ import annotations
from typing import Collection
from typing import Iterable
from typing import Sequence
from gemseo.algos.parameter_space import ParameterSpace
from gemseo.core.dataset import Dataset
from gemseo.core.discipline import MDODiscipline
from gemseo.uncertainty.distributions.distribution import Distribution
from gemseo.uncertainty.sensitivity.analysis import SensitivityAnalysis # noqa: F401
from gemseo.uncertainty.statistics.statistics import Statistics
[docs]def get_available_distributions() -> list[str]:
"""Get the available distributions."""
from gemseo.uncertainty.distributions.factory import DistributionFactory
factory = DistributionFactory()
return factory.available_distributions
[docs]def create_distribution(
variable: str,
distribution_name: str,
dimension: int = 1,
**options,
) -> Distribution:
"""Create a distribution.
Args:
variable: The name of the random variable.
distribution_name: The name of a class
implementing a probability distribution,
e.g. 'OTUniformDistribution' or 'SPDistribution'.
dimension: The dimension of the random variable.
**options: The distribution options.
Examples:
>>> from gemseo.uncertainty.api import create_distribution
>>>
>>> distribution = create_distribution(
... "x", "OTNormalDistribution", dimension=2, mu=1, sigma=2
... )
>>> print(distribution)
Normal(mu=1, sigma=2)
>>> print(distribution.mean, distribution.standard_deviation)
[1. 1.] [2. 2.]
>>> samples = distribution.get_sample(10)
>>> print(samples.shape)
(10, 2)
"""
from gemseo.uncertainty.distributions.factory import DistributionFactory
factory = DistributionFactory()
return factory.create(
distribution_name, variable=variable, dimension=dimension, **options
)
[docs]def get_available_sensitivity_analyses() -> list[str]:
"""Get the available sensitivity analyses."""
from gemseo.uncertainty.sensitivity.factory import SensitivityAnalysisFactory
factory = SensitivityAnalysisFactory()
return factory.available_sensitivity_analyses
[docs]def create_statistics(
dataset: Dataset,
variables_names: Iterable[str] | None = None,
tested_distributions: Sequence[str] | None = None,
fitting_criterion: str = "BIC",
selection_criterion="best",
level: float = 0.05,
name: str | None = None,
) -> Statistics:
"""Create a statistics toolbox, either parametric or empirical.
If parametric, the toolbox selects a distribution from candidates,
based on a fitting criterion and on a selection strategy.
Args:
dataset: A dataset.
variables_names: The variables of interest.
If None, consider all the variables from dataset.
tested_distributions: The names of
the tested distributions.
fitting_criterion: The name of a goodness-of-fit criterion,
measuring how the distribution fits the data.
Use :meth:`.ParametricStatistics.get_criteria`
to get the available criteria.
selection_criterion: The name of a selection criterion
to select a distribution from candidates.
Either 'first' or 'best'.
level: A test level,
i.e. the risk of committing a Type 1 error,
that is an incorrect rejection of a true null hypothesis,
for criteria based on a test hypothesis.
name: A name for the statistics toolbox instance.
If None, use the concatenation of class and dataset names.
Returns:
A statistics toolbox.
Examples:
>>> from gemseo.api import (
... create_discipline,
... create_parameter_space,
... create_scenario
... )
>>> from gemseo.uncertainty.api import create_statistics
>>>
>>> expressions = {"y1": "x1+2*x2", "y2": "x1-3*x2"}
>>> discipline = create_discipline(
... "AnalyticDiscipline", expressions=expressions
... )
>>>
>>> parameter_space = create_parameter_space()
>>> parameter_space.add_random_variable(
... "x1", "OTUniformDistribution", minimum=-1, maximum=1
... )
>>> parameter_space.add_random_variable(
... "x2", "OTNormalDistribution", mu=0.5, sigma=2
... )
>>>
>>> scenario = create_scenario(
... [discipline],
... "DisciplinaryOpt",
... "y1",
... parameter_space,
... scenario_type="DOE"
... )
>>> scenario.execute({'algo': 'OT_MONTE_CARLO', 'n_samples': 100})
>>>
>>> dataset = scenario.export_to_dataset(opt_naming=False)
>>>
>>> statistics = create_statistics(dataset)
>>> mean = statistics.mean()
"""
from gemseo.uncertainty.statistics.empirical import EmpiricalStatistics as EmpStats
from gemseo.uncertainty.statistics.parametric import (
ParametricStatistics as ParamStats,
)
if tested_distributions is None:
statistical_analysis = EmpStats(dataset, variables_names, name)
else:
statistical_analysis = ParamStats(
dataset,
tested_distributions,
variables_names,
fitting_criterion,
level,
selection_criterion,
name,
)
return statistical_analysis
[docs]def create_sensitivity_analysis(
analysis: str,
disciplines: Collection[MDODiscipline],
parameter_space: ParameterSpace,
**options,
) -> SensitivityAnalysis:
"""Create the sensitivity analysis.
Args:
analysis: The name of a sensitivity analysis class.
disciplines: The disciplines.
parameter_space: A parameter space.
**options: The DOE algorithm options.
Returns:
The toolbox for these sensitivity indices.
Examples:
>>> from gemseo.api import create_discipline, create_parameter_space
>>> from gemseo.uncertainty.api import create_sensitivity_analysis
>>>
>>> expressions = {"y1": "x1+2*x2", "y2": "x1-3*x2"}
>>> discipline = create_discipline(
... "AnalyticDiscipline", expressions=expressions
... )
>>>
>>> parameter_space = create_parameter_space()
>>> parameter_space.add_random_variable(
... "x1", "OTUniformDistribution", minimum=-1, maximum=1
... )
>>> parameter_space.add_random_variable(
... "x2", "OTNormalDistribution", mu=0.5, sigma=2
... )
>>>
>>> analysis = create_sensitivity_analysis(
... "CorrelationIndices", [discipline], parameter_space, n_samples=1000
... )
>>> indices = analysis.compute_indices()
"""
from gemseo.uncertainty.sensitivity.factory import SensitivityAnalysisFactory
factory = SensitivityAnalysisFactory()
name = analysis
if "Analysis" not in name:
name += "Analysis"
name = name[0].upper() + name[1:]
return factory.create(name, disciplines, parameter_space, **options)