Source code for gemseo_umdo.monte_carlo_sampler

# Copyright 2021 IRT Saint Exupéry,
# 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
# 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.
"""A Monte Carlo sampler."""
from __future__ import annotations

from typing import Callable

from gemseo.algos.design_space import DesignSpace
from gemseo.algos.doe.lib_openturns import OpenTURNS
from numpy import array
from numpy import hstack
from numpy import vstack
from numpy.typing import NDArray

FunctionType = Callable[[NDArray[float]], NDArray[float]]

[docs]class MonteCarloSampler: """A Monte Carlo sampler taking advantage of the vectorized functions.""" __algo: OpenTURNS """The Monte Carlo algorithm.""" __functions: list[FunctionType] """The functions to sample.""" __input_space: DesignSpace """The input space on which to sample the functions.""" __input_histories: list[NDArray[float]] """One history of the function inputs per call to the sampler.""" __output_histories: list[NDArray[float]] """One history of the function outputs per call to the sampler.""" def __init__(self, input_space: DesignSpace) -> None: """ Args: input_space: The input space on which to sample the functions. """ # noqa:D205 D212 D415 self.__algo = OpenTURNS() self.__algo.algo_name = "OT_MONTE_CARLO" self.__functions = [] self.__input_space = input_space self.__input_histories = [] self.__output_histories = [] self.__all_functions_are_vectorized = True
[docs] def add_function(self, function: FunctionType, is_vectorized: bool = True) -> None: """Add a function to sample. Args: function: A function to sample. is_vectorized: Whether the function is vectorized. """ self.__all_functions_are_vectorized &= is_vectorized self.__functions.append(function)
def __call__( self, n_samples: int, seed: int | None = None ) -> tuple[NDArray[float], NDArray[float]]: """Sample the functions with a Monte Carlo algorithm. Args: n_samples: The number of samples. seed: The seed value. If ``None``, use the [OpenTURNS.seed][gemseo.algos.doe.lib_openturns.OpenTURNS.seed]. Returns: The input and output samples. """ input_samples = self.__algo.compute_doe( self.__input_space, size=n_samples, seed=seed ) if self.__all_functions_are_vectorized: output_samples = [function(input_samples) for function in self.__functions] else: output_samples = [ vstack([function(input_sample) for input_sample in input_samples]) for function in self.__functions ] output_samples = hstack(output_samples) self.__input_histories.append(input_samples) self.__output_histories.append(output_samples) return input_samples, output_samples @property def input_history(self) -> NDArray[float]: """The history of the function inputs.""" if self.__input_histories: return vstack(self.__input_histories) else: return array(()) @property def output_history(self) -> NDArray[float]: """The history of the function outputs.""" if self.__output_histories: return vstack(self.__output_histories) else: return array(())