Source code for deap.tools.mutation

import math
import random

from itertools import repeat

try:
    from collections.abc import Sequence
except ImportError:
    from collections import Sequence

######################################
# GA Mutations                       #
######################################


[docs]def mutGaussian(individual, mu, sigma, indpb): """This function applies a gaussian mutation of mean *mu* and standard deviation *sigma* on the input individual. This mutation expects a :term:`sequence` individual composed of real valued attributes. The *indpb* argument is the probability of each attribute to be mutated. :param individual: Individual to be mutated. :param mu: Mean or :term:`python:sequence` of means for the gaussian addition mutation. :param sigma: Standard deviation or :term:`python:sequence` of standard deviations for the gaussian addition mutation. :param indpb: Independent probability for each attribute to be mutated. :returns: A tuple of one individual. This function uses the :func:`~random.random` and :func:`~random.gauss` functions from the python base :mod:`random` module. """ size = len(individual) if not isinstance(mu, Sequence): mu = repeat(mu, size) elif len(mu) < size: raise IndexError("mu must be at least the size of individual: %d < %d" % (len(mu), size)) if not isinstance(sigma, Sequence): sigma = repeat(sigma, size) elif len(sigma) < size: raise IndexError("sigma must be at least the size of individual: %d < %d" % (len(sigma), size)) for i, m, s in zip(range(size), mu, sigma): if random.random() < indpb: individual[i] += random.gauss(m, s) return individual,
[docs]def mutPolynomialBounded(individual, eta, low, up, indpb): """Polynomial mutation as implemented in original NSGA-II algorithm in C by Deb. :param individual: :term:`Sequence <sequence>` individual to be mutated. :param eta: Crowding degree of the mutation. A high eta will produce a mutant resembling its parent, while a small eta will produce a solution much more different. :param low: A value or a :term:`python:sequence` of values that is the lower bound of the search space. :param up: A value or a :term:`python:sequence` of values that is the upper bound of the search space. :param indpb: Independent probability for each attribute to be mutated. :returns: A tuple of one individual. """ size = len(individual) if not isinstance(low, Sequence): low = repeat(low, size) elif len(low) < size: raise IndexError("low must be at least the size of individual: %d < %d" % (len(low), size)) if not isinstance(up, Sequence): up = repeat(up, size) elif len(up) < size: raise IndexError("up must be at least the size of individual: %d < %d" % (len(up), size)) for i, xl, xu in zip(range(size), low, up): if random.random() <= indpb: x = individual[i] delta_1 = (x - xl) / (xu - xl) delta_2 = (xu - x) / (xu - xl) rand = random.random() mut_pow = 1.0 / (eta + 1.) if rand < 0.5: xy = 1.0 - delta_1 val = 2.0 * rand + (1.0 - 2.0 * rand) * xy ** (eta + 1) delta_q = val ** mut_pow - 1.0 else: xy = 1.0 - delta_2 val = 2.0 * (1.0 - rand) + 2.0 * (rand - 0.5) * xy ** (eta + 1) delta_q = 1.0 - val ** mut_pow x = x + delta_q * (xu - xl) x = min(max(x, xl), xu) individual[i] = x return individual,
[docs]def mutShuffleIndexes(individual, indpb): """Shuffle the attributes of the input individual and return the mutant. The *individual* is expected to be a :term:`sequence`. The *indpb* argument is the probability of each attribute to be moved. Usually this mutation is applied on vector of indices. :param individual: Individual to be mutated. :param indpb: Independent probability for each attribute to be exchanged to another position. :returns: A tuple of one individual. This function uses the :func:`~random.random` and :func:`~random.randint` functions from the python base :mod:`random` module. """ size = len(individual) for i in range(size): if random.random() < indpb: swap_indx = random.randint(0, size - 2) if swap_indx >= i: swap_indx += 1 individual[i], individual[swap_indx] = \ individual[swap_indx], individual[i] return individual,
[docs]def mutFlipBit(individual, indpb): """Flip the value of the attributes of the input individual and return the mutant. The *individual* is expected to be a :term:`sequence` and the values of the attributes shall stay valid after the ``not`` operator is called on them. The *indpb* argument is the probability of each attribute to be flipped. This mutation is usually applied on boolean individuals. :param individual: Individual to be mutated. :param indpb: Independent probability for each attribute to be flipped. :returns: A tuple of one individual. This function uses the :func:`~random.random` function from the python base :mod:`random` module. """ for i in range(len(individual)): if random.random() < indpb: individual[i] = type(individual[i])(not individual[i]) return individual,
[docs]def mutUniformInt(individual, low, up, indpb): """Mutate an individual by replacing attributes, with probability *indpb*, by a integer uniformly drawn between *low* and *up* inclusively. :param individual: :term:`Sequence <sequence>` individual to be mutated. :param low: The lower bound or a :term:`python:sequence` of of lower bounds of the range from which to draw the new integer. :param up: The upper bound or a :term:`python:sequence` of of upper bounds of the range from which to draw the new integer. :param indpb: Independent probability for each attribute to be mutated. :returns: A tuple of one individual. """ size = len(individual) if not isinstance(low, Sequence): low = repeat(low, size) elif len(low) < size: raise IndexError("low must be at least the size of individual: %d < %d" % (len(low), size)) if not isinstance(up, Sequence): up = repeat(up, size) elif len(up) < size: raise IndexError("up must be at least the size of individual: %d < %d" % (len(up), size)) for i, xl, xu in zip(range(size), low, up): if random.random() < indpb: individual[i] = random.randint(xl, xu) return individual,
def mutInversion(individual): """Select two points (indices) in the individual, reverse the order of the attributes between these points [low, high] and return the mutated individual. This implementation allows for the length of the inversion to be 0 and 1, which would cause no change. This mutation is useful in situations where the order/adjacency of elements is important. :param individual: Individual to be mutated. :returns: A tuple of one individual. This function uses the :func:`~random.random` function from the python base :mod:`random` module. """ size = len(individual) if size == 0: return individual, index_one = random.randrange(size) index_two = random.randrange(size) start_index = min(index_one, index_two) end_index = max(index_one, index_two) # Reverse the contents of the individual between the indices individual[start_index:end_index] = individual[start_index:end_index][::-1] return individual, ###################################### # ES Mutations # ######################################
[docs]def mutESLogNormal(individual, c, indpb): r"""Mutate an evolution strategy according to its :attr:`strategy` attribute as described in [Beyer2002]_. First the strategy is mutated according to an extended log normal rule, :math:`\\boldsymbol{\sigma}_t = \\exp(\\tau_0 \mathcal{N}_0(0, 1)) \\left[ \\sigma_{t-1, 1}\\exp(\\tau \mathcal{N}_1(0, 1)), \ldots, \\sigma_{t-1, n} \\exp(\\tau \mathcal{N}_n(0, 1))\\right]`, with :math:`\\tau_0 = \\frac{c}{\\sqrt{2n}}` and :math:`\\tau = \\frac{c}{\\sqrt{2\\sqrt{n}}}`, the the individual is mutated by a normal distribution of mean 0 and standard deviation of :math:`\\boldsymbol{\sigma}_{t}` (its current strategy) then . A recommended choice is ``c=1`` when using a :math:`(10, 100)` evolution strategy [Beyer2002]_ [Schwefel1995]_. :param individual: :term:`Sequence <sequence>` individual to be mutated. :param c: The learning parameter. :param indpb: Independent probability for each attribute to be mutated. :returns: A tuple of one individual. .. [Beyer2002] Beyer and Schwefel, 2002, Evolution strategies - A Comprehensive Introduction .. [Schwefel1995] Schwefel, 1995, Evolution and Optimum Seeking. Wiley, New York, NY """ size = len(individual) t = c / math.sqrt(2. * math.sqrt(size)) t0 = c / math.sqrt(2. * size) n = random.gauss(0, 1) t0_n = t0 * n for indx in range(size): if random.random() < indpb: individual.strategy[indx] *= math.exp(t0_n + t * random.gauss(0, 1)) individual[indx] += individual.strategy[indx] * random.gauss(0, 1) return individual,
__all__ = ['mutGaussian', 'mutPolynomialBounded', 'mutShuffleIndexes', 'mutFlipBit', 'mutUniformInt', 'mutInversion', 'mutESLogNormal']