GeneticAlgorithm  0.5 (beta)
A python framework for rapid GA prototyping
src/GeneticAlgorithm/SelectionOperators.py
Go to the documentation of this file.
00001 import copy
00002 import random
00003 from Core import *
00004 
00005 ## @class SelectLethals
00006 #  @brief Select the individuals to replace based on the population.maximize flag and the population.genSize property
00007 #
00008 #  Select as many individuals as indicated by population.genSize to be replaced during the next crossover operation
00009 class SelectLethals(GeneticOperator):
00010     ## @fn select(self, population)
00011     #  @brief Select the individuals to replace based on the population.maximize flag and the population.genSize property
00012     def select(self, population):        
00013         # Get the population size
00014         n = len(population.individuals)
00015         # Get the amount of offspring to produce (2*m = len(mating_pool))
00016         m = getattr(population, 'genSize', n)
00017         #  Get a fitness vector out of the individual vector        
00018         fitness = [individual.fitness for individual in population.individuals]
00019         indices = range(n)
00020         sortedFitness = sorted(zip(fitness, indices), key=lambda x: x[0])
00021         # Select the m worse individuals in the generation to be replaced
00022         if population.maximize:
00023             L = sortedFitness[:m]
00024         else:
00025             L = sortedFitness[-m:]
00026         # Update the lethals vector
00027         population.lethals = [l[1] for l in L]
00028     # Select individuals for replacement only during the iterate phase of runGA    
00029     iterate     = select
00030 
00031 ## @class KTournament
00032 #  @brief A selection operator that implements the k-tournament algorithm
00033 class KTournament(GeneticOperator):
00034     ## @fn __init__(self, k=2, **kwargs)
00035     #  @brief The genetic operator constructor
00036     #  @param k The number of individuals that will participate in every tournament 
00037     def __init__(self, k=2, **kwargs):
00038         super(KTournament, self).__init__(**kwargs)
00039         self.k = k
00040 
00041     ## @fn selectBest(self, candidates, population)
00042     #  @brief Given a list of candidates and a population, decide which cantidae is the best
00043     #  @param candidates A list of indexes that point to the tournament candiadates
00044     #  @param population A Core.Population object that contains the contender individuals
00045     #  @return The index of the best individual among the candidates
00046     def selectBest(self, contenders, population):
00047         sortedContenders = sorted([(population.individuals[i].fitness,i) for i in contenders], key=lambda x: x[0])
00048         if population.maximize:
00049             return sortedContenders[-1][1]
00050         else:
00051             return sortedContenders[0][1]
00052     
00053     ## @fn select(self, population)
00054     #  @brief Perform the k-tournament selection
00055     # 
00056     #  The k-tournament selection algorithm consists on creating tournaments in which k random individuals participate. The best individual is selected for each tournament, and is selected to belong to the mating pool.
00057     #  M torunaments are performed, where M is equal to population.genSize (or n if this property is not found)
00058     def select(self, population):
00059         # Number of individuals
00060         n = len(population.individuals)
00061         # Get the amount of offspring to produce (2*m = len(mating_pool))
00062         m = getattr(population, 'genSize', n)
00063         # Compute the contenders for each torunament
00064         tournaments = [ [random.randrange(n) for contender in xrange(self.k) ] for tournament in xrange(2*m) ]
00065         # Put the tournament winners on the mating pool
00066         population.matingPool = [self.selectBest(contenders, population) for contenders in tournaments ]
00067     # Make iterate function call select instead
00068     iterate = select
00069                 
00070 ## @class SUSSelection
00071 #  @brief This operator performs stochastic uniform selection over the population, updating the field matingPool
00072 #
00073 #  This class performs SUS for both maximization or minimization, the mating pool is simply a list of indices that point to the parents. If minimization is desired, the population.maximize flag must be set to False.
00074 #  If population.genSize exists, the mating pool will be twice that number (to produce the same number of offspring); If this parameter does not exist, the mating pool will have twice the length of population.individuals
00075 class SUSSelection(GeneticOperator):
00076     def select(self, population):
00077         # Number of individuals
00078         n = len(population.individuals)
00079         # Fitness vector
00080         fit = [ind.fitness for ind in population.individuals]
00081         # Adjust the pdf for minimization
00082         if not population.maximize:
00083             pdf = [0.0]*n
00084             M = max(fit) + (1.0)
00085             for i in xrange(n):
00086                 pdf[i] = M - fit[i]
00087         else:
00088             pdf = fit        
00089         # Normalization factor
00090         F = reduce(lambda x, y: x+y, pdf)
00091         # Cumulative distribution function
00092         cdf = [pdf[0]/F] *n
00093         # Probability distribution function
00094         for i in xrange(1, n):
00095             cdf[i] = cdf[i-1] + pdf[i]/F            
00096         # Get the amount of offspring to produce (2*m = len(mating_pool))
00097         m = getattr(population, 'genSize', n)
00098         # Distance between ticks in SUS -> 1/2*m := 0.5/m
00099         delta = 0.5/m
00100         # Initialize the mating pool
00101         matingPool = [ 0 ] * (2*m)
00102         # SUS implements a roulette with 2*m equidistant ticks, this variable stores the position of the current tick (as a probability)
00103         currentTick = delta * random.random()
00104         # Generate 2*m parent pointers 
00105         for i in xrange(2*m):
00106             # Find the first entry on the cdf that is greater than or equal to the current tick
00107             for slicePointer in xrange(n):
00108                 if cdf[slicePointer] > currentTick:
00109                     break
00110             # The ith element on the maitingPool is slice pointer
00111             matingPool[i] = slicePointer
00112             currentTick += delta
00113             while currentTick > 1.0:
00114                 currentTick -= 1.0
00115         random.shuffle(matingPool)
00116         population.matingPool = matingPool
00117     iterate = select    
 All Classes Namespaces Files Functions Variables