nmoo.noises.gaussian

Random noises to apply to objective functions.

  1"""
  2Random noises to apply to objective functions.
  3"""
  4__docformat__ = "google"
  5
  6from typing import Any, Dict, Optional, Tuple, Union
  7
  8import numpy as np
  9from loguru import logger as logging
 10from pymoo.core.problem import Problem
 11
 12from nmoo.wrapped_problem import WrappedProblem
 13
 14
 15class GaussianNoise(WrappedProblem):
 16    """
 17    A wrapper that adds a (multivariate) gaussian noise to a problem.
 18
 19    Assume that the output of the wrapped problem as an `F` numerical component
 20    (as they almost always do). The following creates a new problem by adding a
 21    `N(0, .2)` noise on all components of `F` (without any covariance):
 22
 23        mean_F = np.array([0., 0.])
 24        cov_F = .2 * np.eye(2)
 25        noisy_problem = nmoo.GaussianNoise(problem, mean_F, cov_F)
 26
 27    Assume that in addition, the problem has a `G` numerical component to which
 28    we would also like to add noise. The following a 0-mean 1-dimensional
 29    gaussian noise along the plane antidiagonal (line with -pi/4 orientation)
 30    to `G`, and the same noise as above to `F`:
 31
 32        mean_F = np.array([0., 0.])
 33        cov_F = .2 * np.eye(2)
 34        mean_G = np.array([0., 0.])
 35        cov_G = np.array([[1., -1.], [-1., 1.]])
 36        noisy_problem = nmoo.GaussianNoise(
 37            problem, {
 38                "F": (mean_F, cov_F),
 39                "G": (mean_G, cov_G),
 40            },
 41        )
 42
 43    """
 44
 45    _generator: np.random.Generator
 46    """Random number generator."""
 47
 48    _parameters: Dict[str, Tuple[np.ndarray, np.ndarray]]
 49    """
 50    Noise parameters. Each entry is a tuple containing the noise's mean vector
 51    and covariance matrix.
 52    """
 53
 54    def __init__(
 55        self,
 56        problem: Problem,
 57        mean: Optional[np.ndarray] = None,
 58        covariance: Optional[Union[float, int, np.ndarray]] = None,
 59        parameters: Optional[Dict[str, Tuple[np.ndarray, np.ndarray]]] = None,
 60        seed: Any = None,
 61        *,
 62        name: str = "gaussian_noise",
 63        **kwargs,
 64    ):
 65        """
 66        Args:
 67            name (str): An optional name for this problem. This will be used
 68                when creating history dump files. Defaults to `gaussian_noise`.
 69            problem (pymoo `Problem`): A non-noisy pymoo problem (or
 70                `nmoo.wrapped_problem.WrappedProblem`).
 71            mean (optional `np.ndarray`): The mean vector of the gaussian
 72                distribution. If specified, the `covariance` argument must also
 73                be specified, and `parameters` must be left to its default
 74                `None`.
 75            covariance (optional `np.ndarray` or number): The covariance
 76                matrix of the gaussian distribution. If specified, the `mean`
 77                argument must also be specified, and `parameters` must be left
 78                to its default `None`. For convenience, a number `v` can be
 79                passed instead of a matrix, in which case the covariance matrix
 80                is set to be `v * I_n`, where `n` is the dimension of the
 81                `mean` vector. Note that `v` is then the variance of every
 82                component of the distribution, **not the standard deviation**!
 83            parameters (optional dict): Gaussian noise parameters, in the form
 84                of a dict mapping the name of an objective to a numpy array
 85                pair (mean, covariance matrix). The set of keys should be a
 86                subset of the final `out` dictionary keys in the wrapped
 87                problem's `_evaluate` method. If specified, the `mean` and
 88                `covariance` arguments must be left to their default `None`.
 89            seed: Seed for
 90                [`numpy.random.default_rng`](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.default_rng)
 91        """
 92        super().__init__(problem, name=name, **kwargs)
 93        if mean is not None and covariance is not None and parameters is None:
 94            if not isinstance(covariance, np.ndarray):
 95                covariance = covariance * np.eye(mean.shape[0])
 96            self._parameters = {"F": (mean, covariance)}
 97        elif mean is None and covariance is None and parameters is not None:
 98            self._parameters = parameters
 99        else:
100            raise ValueError(
101                "Invalid noise specification. Either mean and covariance are "
102                "both set, or a parameters dict is set."
103            )
104        self.reseed(seed)
105
106    def _evaluate(self, x, out, *args, **kwargs):
107        """
108        Calls the wrapped problems's `_evaluate` method and adds a Gaussian
109        noise. Adds the input (`x`), the noisy output, and the noise values to
110        history.
111
112        Example:
113
114            If the wrapped problem's output dict looks like:
115
116                {
117                    "A": (n, m) np.ndarray,
118                    "B": not an np.ndarray
119                }
120
121            then the history will look like this:
122
123                {
124                    "A": an np.ndarray (with the noise added),
125                    "A_noise": an np.ndarray of the same dimension
126                }
127
128        """
129        self._problem._evaluate(x, out, *args, **kwargs)
130        noises: Dict[str, np.ndarray] = {}
131        for k in self._parameters.keys():
132            try:
133                mean, cov = self._parameters[k]
134                noises[k] = self._generator.multivariate_normal(
135                    mean,
136                    cov,
137                    out[k].shape[0],
138                )
139                out[k] += noises[k]
140            except KeyError:
141                logging.error(
142                    "Noise parameter key {} is not present in objective "
143                    "function output keys. No noise will be applied. "
144                    "Objective function keys: {}. ",
145                    k,
146                    str(list(out.keys())),
147                )
148        self.add_to_history_x_out(
149            x, out, **{k + "_noise": v for k, v in noises.items()}
150        )
151
152    def reseed(self, seed: Any) -> None:
153        self._generator = np.random.default_rng(seed)
154        if isinstance(self._problem, WrappedProblem):
155            self._problem.reseed(seed)
class GaussianNoise(nmoo.wrapped_problem.WrappedProblem):
 16class GaussianNoise(WrappedProblem):
 17    """
 18    A wrapper that adds a (multivariate) gaussian noise to a problem.
 19
 20    Assume that the output of the wrapped problem as an `F` numerical component
 21    (as they almost always do). The following creates a new problem by adding a
 22    `N(0, .2)` noise on all components of `F` (without any covariance):
 23
 24        mean_F = np.array([0., 0.])
 25        cov_F = .2 * np.eye(2)
 26        noisy_problem = nmoo.GaussianNoise(problem, mean_F, cov_F)
 27
 28    Assume that in addition, the problem has a `G` numerical component to which
 29    we would also like to add noise. The following a 0-mean 1-dimensional
 30    gaussian noise along the plane antidiagonal (line with -pi/4 orientation)
 31    to `G`, and the same noise as above to `F`:
 32
 33        mean_F = np.array([0., 0.])
 34        cov_F = .2 * np.eye(2)
 35        mean_G = np.array([0., 0.])
 36        cov_G = np.array([[1., -1.], [-1., 1.]])
 37        noisy_problem = nmoo.GaussianNoise(
 38            problem, {
 39                "F": (mean_F, cov_F),
 40                "G": (mean_G, cov_G),
 41            },
 42        )
 43
 44    """
 45
 46    _generator: np.random.Generator
 47    """Random number generator."""
 48
 49    _parameters: Dict[str, Tuple[np.ndarray, np.ndarray]]
 50    """
 51    Noise parameters. Each entry is a tuple containing the noise's mean vector
 52    and covariance matrix.
 53    """
 54
 55    def __init__(
 56        self,
 57        problem: Problem,
 58        mean: Optional[np.ndarray] = None,
 59        covariance: Optional[Union[float, int, np.ndarray]] = None,
 60        parameters: Optional[Dict[str, Tuple[np.ndarray, np.ndarray]]] = None,
 61        seed: Any = None,
 62        *,
 63        name: str = "gaussian_noise",
 64        **kwargs,
 65    ):
 66        """
 67        Args:
 68            name (str): An optional name for this problem. This will be used
 69                when creating history dump files. Defaults to `gaussian_noise`.
 70            problem (pymoo `Problem`): A non-noisy pymoo problem (or
 71                `nmoo.wrapped_problem.WrappedProblem`).
 72            mean (optional `np.ndarray`): The mean vector of the gaussian
 73                distribution. If specified, the `covariance` argument must also
 74                be specified, and `parameters` must be left to its default
 75                `None`.
 76            covariance (optional `np.ndarray` or number): The covariance
 77                matrix of the gaussian distribution. If specified, the `mean`
 78                argument must also be specified, and `parameters` must be left
 79                to its default `None`. For convenience, a number `v` can be
 80                passed instead of a matrix, in which case the covariance matrix
 81                is set to be `v * I_n`, where `n` is the dimension of the
 82                `mean` vector. Note that `v` is then the variance of every
 83                component of the distribution, **not the standard deviation**!
 84            parameters (optional dict): Gaussian noise parameters, in the form
 85                of a dict mapping the name of an objective to a numpy array
 86                pair (mean, covariance matrix). The set of keys should be a
 87                subset of the final `out` dictionary keys in the wrapped
 88                problem's `_evaluate` method. If specified, the `mean` and
 89                `covariance` arguments must be left to their default `None`.
 90            seed: Seed for
 91                [`numpy.random.default_rng`](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.default_rng)
 92        """
 93        super().__init__(problem, name=name, **kwargs)
 94        if mean is not None and covariance is not None and parameters is None:
 95            if not isinstance(covariance, np.ndarray):
 96                covariance = covariance * np.eye(mean.shape[0])
 97            self._parameters = {"F": (mean, covariance)}
 98        elif mean is None and covariance is None and parameters is not None:
 99            self._parameters = parameters
100        else:
101            raise ValueError(
102                "Invalid noise specification. Either mean and covariance are "
103                "both set, or a parameters dict is set."
104            )
105        self.reseed(seed)
106
107    def _evaluate(self, x, out, *args, **kwargs):
108        """
109        Calls the wrapped problems's `_evaluate` method and adds a Gaussian
110        noise. Adds the input (`x`), the noisy output, and the noise values to
111        history.
112
113        Example:
114
115            If the wrapped problem's output dict looks like:
116
117                {
118                    "A": (n, m) np.ndarray,
119                    "B": not an np.ndarray
120                }
121
122            then the history will look like this:
123
124                {
125                    "A": an np.ndarray (with the noise added),
126                    "A_noise": an np.ndarray of the same dimension
127                }
128
129        """
130        self._problem._evaluate(x, out, *args, **kwargs)
131        noises: Dict[str, np.ndarray] = {}
132        for k in self._parameters.keys():
133            try:
134                mean, cov = self._parameters[k]
135                noises[k] = self._generator.multivariate_normal(
136                    mean,
137                    cov,
138                    out[k].shape[0],
139                )
140                out[k] += noises[k]
141            except KeyError:
142                logging.error(
143                    "Noise parameter key {} is not present in objective "
144                    "function output keys. No noise will be applied. "
145                    "Objective function keys: {}. ",
146                    k,
147                    str(list(out.keys())),
148                )
149        self.add_to_history_x_out(
150            x, out, **{k + "_noise": v for k, v in noises.items()}
151        )
152
153    def reseed(self, seed: Any) -> None:
154        self._generator = np.random.default_rng(seed)
155        if isinstance(self._problem, WrappedProblem):
156            self._problem.reseed(seed)

A wrapper that adds a (multivariate) gaussian noise to a problem.

Assume that the output of the wrapped problem as an F numerical component (as they almost always do). The following creates a new problem by adding a N(0, .2) noise on all components of F (without any covariance):

mean_F = np.array([0., 0.])
cov_F = .2 * np.eye(2)
noisy_problem = nmoo.GaussianNoise(problem, mean_F, cov_F)

Assume that in addition, the problem has a G numerical component to which we would also like to add noise. The following a 0-mean 1-dimensional gaussian noise along the plane antidiagonal (line with -pi/4 orientation) to G, and the same noise as above to F:

mean_F = np.array([0., 0.])
cov_F = .2 * np.eye(2)
mean_G = np.array([0., 0.])
cov_G = np.array([[1., -1.], [-1., 1.]])
noisy_problem = nmoo.GaussianNoise(
    problem, {
        "F": (mean_F, cov_F),
        "G": (mean_G, cov_G),
    },
)
GaussianNoise( problem: pymoo.core.problem.Problem, mean: Union[numpy.ndarray, NoneType] = None, covariance: Union[float, int, numpy.ndarray, NoneType] = None, parameters: Union[Dict[str, Tuple[numpy.ndarray, numpy.ndarray]], NoneType] = None, seed: Any = None, *, name: str = 'gaussian_noise', **kwargs)
 55    def __init__(
 56        self,
 57        problem: Problem,
 58        mean: Optional[np.ndarray] = None,
 59        covariance: Optional[Union[float, int, np.ndarray]] = None,
 60        parameters: Optional[Dict[str, Tuple[np.ndarray, np.ndarray]]] = None,
 61        seed: Any = None,
 62        *,
 63        name: str = "gaussian_noise",
 64        **kwargs,
 65    ):
 66        """
 67        Args:
 68            name (str): An optional name for this problem. This will be used
 69                when creating history dump files. Defaults to `gaussian_noise`.
 70            problem (pymoo `Problem`): A non-noisy pymoo problem (or
 71                `nmoo.wrapped_problem.WrappedProblem`).
 72            mean (optional `np.ndarray`): The mean vector of the gaussian
 73                distribution. If specified, the `covariance` argument must also
 74                be specified, and `parameters` must be left to its default
 75                `None`.
 76            covariance (optional `np.ndarray` or number): The covariance
 77                matrix of the gaussian distribution. If specified, the `mean`
 78                argument must also be specified, and `parameters` must be left
 79                to its default `None`. For convenience, a number `v` can be
 80                passed instead of a matrix, in which case the covariance matrix
 81                is set to be `v * I_n`, where `n` is the dimension of the
 82                `mean` vector. Note that `v` is then the variance of every
 83                component of the distribution, **not the standard deviation**!
 84            parameters (optional dict): Gaussian noise parameters, in the form
 85                of a dict mapping the name of an objective to a numpy array
 86                pair (mean, covariance matrix). The set of keys should be a
 87                subset of the final `out` dictionary keys in the wrapped
 88                problem's `_evaluate` method. If specified, the `mean` and
 89                `covariance` arguments must be left to their default `None`.
 90            seed: Seed for
 91                [`numpy.random.default_rng`](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.default_rng)
 92        """
 93        super().__init__(problem, name=name, **kwargs)
 94        if mean is not None and covariance is not None and parameters is None:
 95            if not isinstance(covariance, np.ndarray):
 96                covariance = covariance * np.eye(mean.shape[0])
 97            self._parameters = {"F": (mean, covariance)}
 98        elif mean is None and covariance is None and parameters is not None:
 99            self._parameters = parameters
100        else:
101            raise ValueError(
102                "Invalid noise specification. Either mean and covariance are "
103                "both set, or a parameters dict is set."
104            )
105        self.reseed(seed)
Arguments:
  • name (str): An optional name for this problem. This will be used when creating history dump files. Defaults to gaussian_noise.
  • problem (pymoo Problem): A non-noisy pymoo problem (or nmoo.wrapped_problem.WrappedProblem).
  • mean (optional np.ndarray): The mean vector of the gaussian distribution. If specified, the covariance argument must also be specified, and parameters must be left to its default None.
  • covariance (optional np.ndarray or number): The covariance matrix of the gaussian distribution. If specified, the mean argument must also be specified, and parameters must be left to its default None. For convenience, a number v can be passed instead of a matrix, in which case the covariance matrix is set to be v * I_n, where n is the dimension of the mean vector. Note that v is then the variance of every component of the distribution, not the standard deviation!
  • parameters (optional dict): Gaussian noise parameters, in the form of a dict mapping the name of an objective to a numpy array pair (mean, covariance matrix). The set of keys should be a subset of the final out dictionary keys in the wrapped problem's _evaluate method. If specified, the mean and covariance arguments must be left to their default None.
  • seed: Seed for numpy.random.default_rng
def reseed(self, seed: Any) -> None:
153    def reseed(self, seed: Any) -> None:
154        self._generator = np.random.default_rng(seed)
155        if isinstance(self._problem, WrappedProblem):
156            self._problem.reseed(seed)

Recursively resets the internal random state of the problem. See the numpy documentation for details about acceptable seeds.

Inherited Members
nmoo.wrapped_problem.WrappedProblem
add_to_history
add_to_history_x_out
all_layers
depth
dump_all_histories
dump_history
ground_problem
innermost_wrapper
start_new_run
pymoo.core.problem.Problem
evaluate
do
nadir_point
ideal_point
pareto_front
pareto_set
has_bounds
has_constraints
bounds
name
calc_constraint_violation