Source code for zellij.utils.operators

# @Author: Thomas Firmin <tfirmin>
# @Date:   2022-05-06T12:07:46+02:00
# @Email:  thomas.firmin@univ-lille.fr
# @Project: Zellij
# @Last modified by:   tfirmin
# @Last modified time: 2022-10-03T22:36:06+02:00
# @License: CeCILL-C (http://www.cecill.info/index.fr.html)

from zellij.core.addons import Mutator, Crossover, Selector
from zellij.core.variables import Constant
import numpy as np
from deap import tools


[docs]class NeighborMutation(Mutator): """NeighborMutation Based on `DEAP <https://deap.readthedocs.io/>`_. It is a :ref:`spadd` which defines a mutation. The mutation itself is based on the neighbor :ref:`addons` defined for each :ref:`var` of the :ref:`sp`. See :ref:`nbh`. Parameters ---------- probability : float Probaility for an individual to be mutated. search_space : :ref:`sp` Targeted :ref:`sp`. Attributes ---------- probability """ def __init__(self, probability, search_space=None): assert ( probability > 0 and probability <= 1 ), f"Probability must be comprised in ]0,1], got {probability}" self.probability = probability super(Mutator, self).__init__(search_space) @Mutator.target.setter def target(self, search_space): if search_space: # assert isinstance( # search_space, Searchspace # ), f""" Target object must be a :ref:`sp` # for {self.__class__.__name__}, got {search_space}""" assert all( hasattr(val, "neighbor") for val in search_space.values ), f"""For {self.__class__.__name__} values of target object must have a `neighbor` method. When defining the :ref:`sp`, user must define the `neighbor` kwarg before the `mutation` kwarg. ex:\n >>> ContinuousSearchspace(values, loss, neighbor=..., mutation=...) """ self._target = search_space def _build(self, toolbox): toolbox.register("mutate", self) def __call__(self, individual): # For each dimension of a solution draw a probability to be muted for val in self.target.values: if np.random.random() < self.probability and not isinstance( val, Constant ): # Get a neighbor of the selected attribute individual[val._idx] = val.neighbor(individual[val._idx]) return (individual,)
[docs]class DeapTournament(Selector): """DeapTournament Based on `DEAP <https://deap.readthedocs.io/>`_ tournament. :ref:`spadd` defining a selection method. Parameters ---------- size : int Size of the tournament. search_space : :ref:`sp` Targeted :ref:`sp`. Attributes ---------- size """ def __init__(self, size, search_space=None): assert size > 0, f"Size must be an int > 0, got {size}" self.size = size super(Selector, self).__init__(search_space) @Mutator.target.setter def target(self, search_space): if search_space: # assert isinstance( # search_space, Searchspace # ), f""" Target object must be a :ref:`sp` # for {self.__class__.__name__}, got {search_space}""" assert all( hasattr(val, "neighbor") for val in search_space.values ), f"""For {self.__class__.__name__} values of target object must have a `neighbor` method. When defining the :ref:`sp`, user must define the `neighbor` kwarg before the `mutation` kwarg. ex:\n >>> ContinuousSearchspace(values, loss, neighbor=..., mutation=...) """ self._target = search_space def _build(self, toolbox): toolbox.register("select", tools.selTournament, tournsize=self.size) self.toolbox = toolbox def __call__(self, population, k): return list( map(self.toolbox.clone, self.toolbox.select(population, k=k)) )
[docs]class DeapOnePoint(Crossover): """DeapOnePoint Based on `DEAP <https://deap.readthedocs.io/>`_ cxOnePoint. :ref:`spadd` defining a crossover method. Parameters ---------- search_space : :ref:`sp` Targeted :ref:`sp`. """ def __init__(self, search_space=None): super(Crossover, self).__init__(search_space) @Mutator.target.setter def target(self, search_space): if search_space: # assert isinstance( # search_space, Searchspace # ), f""" Target object must be a :ref:`sp` # for {self.__class__.__name__}, got {search_space}""" assert all( hasattr(val, "neighbor") for val in search_space.values ), f"""For {self.__class__.__name__} values of target object must have a `neighbor` method. When defining the :ref:`sp`, user must define the `neighbor` kwarg before the `mutation` kwarg. ex:\n >>> ContinuousSearchspace(values, loss, neighbor=..., mutation=...) """ self._target = search_space def _build(self, toolbox): toolbox.register("mate", tools.cxOnePoint) self.toolbox = toolbox def __call__(self, children1, children2): self.toolbox.mate(children1, children2)