classGASelection(metaclass=SelectionMeta): ''' Class for providing an interface to easily extend the behavior of selection operation. '''
defselect(self, population, fitness): ''' Called when we need to select parents from a population to later breeding. :param population: The current population. :type population: GAPopulation :return parents: Two selected individuals for crossover. :type parents: Tuple of tow GAIndividual objects. ''' raise NotImplementedError
from random import random from bisect import bisect_right from itertools import accumulate
from ...plugin_interfaces.operators.selection import GASelection
classRouletteWheelSelection(GASelection): def__init__(self): ''' Selection operator with fitness proportionate selection(FPS) or so-called roulette-wheel selection implementation. ''' pass
defselect(self, population, fitness): ''' Select a pair of parent using FPS algorithm. ''' # Normalize fitness values for all individuals. fit = [fitness(indv) for indv in population.individuals] min_fit = min(fit) fit = [(i - min_fit) for i in fit]
# Create roulette wheel. sum_fit = sum(fit) wheel = list(accumulate([i/sum_fit for i in fit]))
# Select a father and a mother. father_idx = bisect_right(wheel, random()) father = population[father_idx] mother_idx = (father_idx + 1) % len(wheel) mother = population[mother_idx]
from ...plugin_interfaces.operators.selection import GASelection
classTournamentSelection(GASelection): def__init__(self, tournament_size=2): ''' Selection operator using Tournament Strategy with tournament size equals to two by default. ''' self.tournament_size = tournament_size
defselect(self, population, fitness): ''' Select a pair of parent using Tournament strategy. ''' # Competition function. complete = lambda competitors: max(competitors, key=fitness)
# Check validity of tournament size. if self.tournament_size >= len(population): msg = 'Tournament size({}) is larger than population size({})' raise ValueError(msg.format(self.tournament_size, len(population)))
# Pick winners of two groups as parent. competitors_1 = sample(population.individuals, self.tournament_size) competitors_2 = sample(population.individuals, self.tournament_size) father, mother = complete(competitors_1), complete(competitors_2)
from random import random from itertools import accumulate from bisect import bisect_right
from ...plugin_interfaces.operators.selection import GASelection
classLinearRankingSelection(GASelection): def__init__(self, pmin=0.1, pmax=0.9): ''' Selection operator using Linear Ranking selection method. Reference: Baker J E. Adaptive selection methods for genetic algorithms[C]//Proceedings of an International Conference on Genetic Algorithms and their applications. 1985: 101-111. ''' # Selection probabilities for the worst and best individuals. self.pmin, self.pmax = pmin, pmax
defselect(self, population, fitness): ''' Select a pair of parent individuals using linear ranking method. ''' # Individual number. NP = len(population)
# Add rank to all individuals in population. sorted_indvs = sorted(population.individuals, key=fitness, reverse=True)
# Assign selection probabilities linearly. # NOTE: Here the rank i belongs to {1, ..., N} p = lambda i: (self.pmin + (self.pmax - self.pmin)*(i-1)/(NP-1)) probabilities = [self.pmin] + [p(i) for i in range(2, NP)] + [self.pmax]
# Normalize probabilities. psum = sum(probabilities) wheel = list(accumulate([p/psum for p in probabilities]))
from random import random from itertools import accumulate from bisect import bisect_right
from ...plugin_interfaces.operators.selection import GASelection
classExponentialRankingSelection(GASelection): def__init__(self, base=0.5): ''' Selection operator using Exponential Ranking selection method. :param base: The base of exponent :type base: float in range (0.0, 1.0) ''' ifnot (0.0 < base < 1.0): raise ValueError('The base of exponent c must in range (0.0, 1.0)')
self.base = base
defselect(self, population, fitness): ''' Select a pair of parent individuals using exponential ranking method. ''' # Individual number. NP = len(population)
# NOTE: Here the rank i belongs to {1, ..., N} p = lambda i: self.base**(NP - i) probabilities = [p(i) for i in range(1, NP + 1)]
# Normalize probabilities. psum = sum(probabilities) wheel = list(accumulate([p/psum for p in probabilities]))
Shukla, Anupriya, Hari Mohan Pandey, and Deepti Mehrotra. “Comparative review of selection techniques in genetic algorithm.” Futuristic Trends on Computational Analysis and Knowledge Management (ABLAZE), 2015 International Conference on. IEEE, 2015.