Source code for paref.pareto_reflections.avoid_points

import numbers
from typing import Union

import numpy as np

from paref.interfaces.pareto_reflections.pareto_reflection import ParetoReflection


[docs] class AvoidPoints(ParetoReflection): """Avoid certain areas/points (Pareto reflection) When to use ----------- This Pareto reflection should be used if Pareto points are desired which have a minimum distance to some points in each component What it does ------------ The Pareto points of this map are all the Pareto points which have distance at least epsilon (to be specified) in each component Mathematical formula -------------------- Denote by D the set of points which should be avoided, let epsilon be some positive real number and n some nadir (i.e. n dominated by all points). Then, .. math:: p(x) = n if x plus epsilon is dominated or equal to d for some d in D and .. math:: p(x) = x else. Notice that each so found Pareto point has distance at least epsilon in each component from every point in D. Examples -------- Define the nadir and the points which should be avoided >>> import numpy as np >>> nadir, epsilon_avoiding_points, epsilon = np.array([3,7]), np.array([[2,1],[1,5]]), 1 Initialize the EpsilonAvoiding >>> pareto_reflection = AvoidPoints(nadir=nadir, epsilon_avoiding_points=epsilon_avoiding_points, \ epsilon=epsilon) Calling it to (1,1), i.e. calculating .. math:: p(1,1)=(3,7) since (1,1) is dominated by (2,1)-1 yields: >>> pareto_reflection(np.ones(2)) array([3, 7]) """ def __init__(self, nadir: np.ndarray, epsilon_avoiding_points: np.ndarray, epsilon: Union[numbers.Real, np.ndarray]): """Specify the nadir and the to be avoided points Parameters ---------- nadir : np.ndarray nadir (dominated by all points) stored in 1 dimensional array of length n epsilon_avoiding_points : np.ndarray avoided points stored in 2-dimensional array with first dimension corresponding to the points epsilon : Union[numbers.Real, np.ndarray]) value which is subtracted from avoided points """ if nadir.shape != epsilon_avoiding_points.shape and nadir.shape != epsilon_avoiding_points[0].shape: raise ValueError('Nadir and avoiding points need to be 2-dimensional numpy arrays of equal shape!') # TBA: error handling rest if not isinstance(epsilon, numbers.Real) and epsilon.shape != nadir.shape: raise ValueError('Epsilon must be a Real Number or a numpy array of same shape as nadir!') if np.any(epsilon < 0): raise ValueError('Epsilon must be positive!') self.nadir = nadir self.epsilon = epsilon self.epsilon_avoiding_points = epsilon_avoiding_points
[docs] def __call__(self, x: np.ndarray): """Calculate the epsilon avoiding function Parameters ---------- x : np.ndarray input vector stored in 1 dimensional array of length n Returns ------- float value of the epsilon avoiding function """ if len(x.shape) != 1: raise ValueError(f'Input x must be of dimension 1! Shape of x is {x.shape}.') for point in self.epsilon_avoiding_points: if np.all(point - self.epsilon <= x): return self.nadir return x
@property def dimension_codomain(self) -> int: return len(self.nadir) @property def dimension_domain(self) -> int: return len(self.nadir)