import random
from jmetal.core.operator import Mutation
from jmetal.core.solution import BinarySolution, Solution, FloatSolution, IntegerSolution, PermutationSolution
"""
.. module:: mutation
:platform: Unix, Windows
:synopsis: Module implementing mutation operators.
.. moduleauthor:: Antonio J. Nebro <antonio@lcc.uma.es>, Antonio Benítez-Hidalgo <antonio.b@uma.es>
"""
[docs]class NullMutation(Mutation[Solution]):
def __init__(self):
super(NullMutation, self).__init__(probability=0)
[docs] def execute(self, solution: Solution) -> Solution:
return solution
[docs] def get_name(self):
return 'Null mutation'
[docs]class BitFlipMutation(Mutation[BinarySolution]):
def __init__(self, probability: float):
super(BitFlipMutation, self).__init__(probability=probability)
[docs] def execute(self, solution: BinarySolution) -> BinarySolution:
for i in range(solution.number_of_variables):
for j in range(len(solution.variables[i])):
rand = random.random()
if rand <= self.probability:
solution.variables[i][j] = True if solution.variables[i][j] is False else False
return solution
[docs] def get_name(self):
return 'BitFlip mutation'
[docs]class PolynomialMutation(Mutation[FloatSolution]):
def __init__(self, probability: float, distribution_index: float = 0.20):
super(PolynomialMutation, self).__init__(probability=probability)
self.distribution_index = distribution_index
[docs] def execute(self, solution: FloatSolution) -> FloatSolution:
for i in range(solution.number_of_variables):
rand = random.random()
if rand <= self.probability:
y = solution.variables[i]
yl, yu = solution.lower_bound[i], solution.upper_bound[i]
if yl == yu:
y = yl
else:
delta1 = (y - yl) / (yu - yl)
delta2 = (yu - y) / (yu - yl)
rnd = random.random()
mut_pow = 1.0 / (self.distribution_index + 1.0)
if rnd <= 0.5:
xy = 1.0 - delta1
val = 2.0 * rnd + (1.0 - 2.0 * rnd) * (pow(xy, self.distribution_index + 1.0))
deltaq = pow(val, mut_pow) - 1.0
else:
xy = 1.0 - delta2
val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * (pow(xy, self.distribution_index + 1.0))
deltaq = 1.0 - pow(val, mut_pow)
y += deltaq * (yu - yl)
if y < solution.lower_bound[i]:
y = solution.lower_bound[i]
if y > solution.upper_bound[i]:
y = solution.upper_bound[i]
solution.variables[i] = y
return solution
[docs] def get_name(self):
return 'Polynomial mutation'
[docs]class IntegerPolynomialMutation(Mutation[IntegerSolution]):
def __init__(self, probability: float, distribution_index: float = 0.20):
super(IntegerPolynomialMutation, self).__init__(probability=probability)
self.distribution_index = distribution_index
[docs] def execute(self, solution: IntegerSolution) -> IntegerSolution:
for i in range(solution.number_of_variables):
if random.random() <= self.probability:
y = solution.variables[i]
yl, yu = solution.lower_bound[i], solution.upper_bound[i]
if yl == yu:
y = yl
else:
delta1 = (y - yl) / (yu - yl)
delta2 = (yu - y) / (yu - yl)
mut_pow = 1.0 / (self.distribution_index + 1.0)
rnd = random.random()
if rnd <= 0.5:
xy = 1.0 - delta1
val = 2.0 * rnd + (1.0 - 2.0 * rnd) * (xy ** (self.distribution_index + 1.0))
deltaq = val ** mut_pow - 1.0
else:
xy = 1.0 - delta2
val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * (xy ** (self.distribution_index + 1.0))
deltaq = 1.0 - val ** mut_pow
y += deltaq * (yu - yl)
if y < solution.lower_bound[i]:
y = solution.lower_bound[i]
if y > solution.upper_bound[i]:
y = solution.upper_bound[i]
solution.variables[i] = int(round(y))
return solution
[docs] def get_name(self):
return 'Polynomial mutation (Integer)'
[docs]class SimpleRandomMutation(Mutation[FloatSolution]):
def __init__(self, probability: float):
super(SimpleRandomMutation, self).__init__(probability=probability)
[docs] def execute(self, solution: FloatSolution) -> FloatSolution:
for i in range(solution.number_of_variables):
rand = random.random()
if rand <= self.probability:
solution.variables[i] = solution.lower_bound[i] + \
(solution.upper_bound[i] - solution.lower_bound[i]) * random.random()
return solution
[docs] def get_name(self):
return 'Simple random_search mutation'
[docs]class PermutationSwapMutation(Mutation[PermutationSolution]):
[docs] def execute(self, solution: PermutationSolution) -> PermutationSolution:
rand = random.random()
if rand <= self.probability:
pos_one, pos_two = random.sample(range(solution.number_of_variables - 1), 2)
solution.variables[pos_one], solution.variables[pos_two] = \
solution.variables[pos_two], solution.variables[pos_one]
return solution
[docs] def get_name(self):
return 'Permutation Swap mutation'
[docs]class ScrambleMutation(Mutation[PermutationSolution]):
[docs] def execute(self, solution: PermutationSolution) -> PermutationSolution:
for i in range(solution.number_of_variables):
rand = random.random()
if rand <= self.probability:
point1 = random.randint(0, len(solution.variables[i]))
point2 = random.randint(0, len(solution.variables[i]) - 1)
if point2 >= point1:
point2 += 1
else:
point1, point2 = point2, point1
if point2 - point1 >= 20:
point2 = point1 + 20
values = solution.variables[i][point1:point2]
solution.variables[i][point1:point2] = random.sample(values, len(values))
return solution
[docs] def get_name(self):
return 'Scramble'