Source code for optuna.samplers.nsgaii._crossovers._spx

from typing import Optional

import numpy as np

from optuna._experimental import experimental_class
from optuna.samplers.nsgaii._crossovers._base import BaseCrossover
from optuna.study import Study


[docs]@experimental_class("3.0.0") class SPXCrossover(BaseCrossover): """Simplex Crossover operation used by :class:`~optuna.samplers.NSGAIISampler`. Uniformly samples child individuals from within a single simplex that is similar to the simplex produced by the parent individual. For further information about SPX crossover, please refer to the following paper: - `Shigeyoshi Tsutsui and Shigeyoshi Tsutsui and David E. Goldberg and David E. Goldberg and Kumara Sastry and Kumara Sastry Progress Toward Linkage Learning in Real-Coded GAs with Simplex Crossover. IlliGAL Report. 2000. <https://www.researchgate.net/publication/2388486_Progress_Toward_Linkage_Learning_in_Real-Coded_GAs_with_Simplex_Crossover>`_ Args: epsilon: Expansion rate. If not specified, defaults to ``sqrt(len(search_space) + 2)``. """ n_parents = 3 def __init__(self, epsilon: Optional[float] = None) -> None: self._epsilon = epsilon
[docs] def crossover( self, parents_params: np.ndarray, rng: np.random.RandomState, study: Study, search_space_bounds: np.ndarray, ) -> np.ndarray: # https://www.researchgate.net/publication/2388486_Progress_Toward_Linkage_Learning_in_Real-Coded_GAs_with_Simplex_Crossover # Section 2 A Brief Review of SPX n = self.n_parents - 1 G = np.mean(parents_params, axis=0) # Equation (1). rs = np.power(rng.rand(n), 1 / (np.arange(n) + 1)) # Equation (2). epsilon = np.sqrt(len(search_space_bounds) + 2) if self._epsilon is None else self._epsilon xks = [G + epsilon * (pk - G) for pk in parents_params] # Equation (3). ck = 0 # Equation (4). for k in range(1, self.n_parents): ck = rs[k - 1] * (xks[k - 1] - xks[k] + ck) child_params = xks[-1] + ck # Equation (5). return child_params