Source code for pyec.distribution.ec.selectors

from numpy import *
import copy, traceback, sys
from pyec.distribution.basic import PopulationDistribution
from pyec.util.partitions import Point, Partition, ScoreTree, Segment
from pyec.util.TernaryString import TernaryString

import logging
logger = logging.getLogger(__file__)

[docs]class Selection(PopulationDistribution): """A selection method""" pass
[docs]class BestSelection(Selection): def __init__(self, config): super(Selection, self).__init__(config) self.best = None self.score = None def __call__(self): return self.best def update(self, generation, population): for x, s in population: if s >= self.score: self.best = x self.score = s
[docs]class EvolutionStrategySelection(Selection): def __init__(self, config): super(EvolutionStrategySelection, self).__init__(config) self.total = 0 self.mu = config.mu self.plus = config.selection == 'plus' # plus or comma selection, for ES def __call__(self): idx = random.randint(0,self.mu-1) return self.population[idx] def batch(self, popSize): if self.plus: return self.population \ + [self.__call__() for i in xrange(popSize - self.mu)] else: return [self.__call__() for i in xrange(popSize)]
[docs] def update(self, generation, population): """the population is ordered by score, take the first mu as parents""" self.population = [x for x,s in population][:self.mu]
[docs]class Proportional(Selection): def __init__(self, config): super(Proportional, self).__init__(config) self.total = 0 self.matchedPopulation = [] def __call__(self): rnd = random.random_sample() * self.total for x,amt in self.matchedPopulation: if amt >= rnd: return x return self.matchedPopulation[-1][0] def batch(self, popSize): return [self.__call__() for i in xrange(popSize)] def update(self, generation, population): self.population = copy.deepcopy(population) self.total = sum([s for x,s in population]) self.matchedPopulation = [] amt = 0 for x,s in population: amt += s self.matchedPopulation.append((x,amt)) return self.population
[docs]class Tournament(Selection): def __init__(self, config): super(Tournament, self).__init__(config) self.pressure = config.selectionPressure self.total = 0 self.matchedPopulation = [] def __call__(self): rnd = random.random_sample() * self.total for x,amt in self.matchedPopulation: if amt >= rnd: return x return self.matchedPopulation[-1][0] def batch(self, popSize): return [self.__call__() for i in xrange(popSize)] def update(self, generation, population): self.population = copy.deepcopy(population) self.matchedPopulation = [] amt = self.pressure self.total = 0 for x,s in population: self.matchedPopulation.append((x,amt)) self.total += amt amt *= (1 - self.pressure) return self.population
[docs]class Ranker(object): def __call__(self, rank, popSize): pass
[docs]class LinearRanker(Ranker): def __init__(self, pressure): """pressure between 1.0 and 2.0""" self.pressure = pressure def __call__(self, rank, popSize): return 2 - self.pressure + (2 * (self.pressure-1))* ((rank-1.0)/(popSize - 1.0))
[docs]class NonlinearRanker(Ranker): def __init__(self, pressure, popSize): self.pressure = pressure self.coeffs = [self.pressure for i in xrange(popSize)] self.coeffs[0] -= popSize self.root = roots(self.coeffs)[0].real def __call__(self, rank, popSize): """ root is root of (pressure * sum_k=0^(popSize-1) x^k) - popSize * x ^(popSize - 1)""" return self.root ** (rank - 1.0)
[docs]class Ranking(Selection): """Takes a ranking function which weights individuals according to rank Rank is 1 for lowest, K for highest in population of size K""" def __init__(self, config): super(Ranking, self).__init__(config) self.ranker = config.ranker self.total = 0 self.matchedPopulation = [] def __call__(self): rnd = random.random_sample() * self.total for x,amt in self.matchedPopulation: if amt >= rnd: return x return self.matchedPopulation[-1][0] def density(self, idx): return self.ranker(idx, len(self.matchedPopulation)) / self.total def batch(self, popSize): return [self.__call__() for i in xrange(popSize)] def update(self, generation, population): self.population = population # copy.deepcopy(population) self.matchedPopulation = [] amt = 0 idx = len(population) for x,s in population: amt += self.ranker(idx, len(population)) self.matchedPopulation.append((x,amt)) idx -= 1 self.total = amt return self.population
[docs]class Elitist(Selection): def __init__(self, config): super(Elitist, self).__init__(config) self.maxScore = -1e100 self.maxOrg = None self.population = None def batch(self, popSize): return self.population def update(self, generation, population): if population[0][1] > self.maxScore or self.maxOrg is None: self.maxScore = population[0][1] self.maxOrg = population[0][0] self.population = copy.deepcopy(population) else: self.population = [(self.maxOrg, self.maxScore)] self.population.extend(population) self.population = self.population[:-1]
[docs]class Annealing(Selection): def __init__(self, config): super(Annealing, self).__init__(config) self.n = 0 self.ids = [] self.segment = None self.activeField = config.activeField config.taylorCenter = 1.0 if not hasattr(config, 'taylorDepth'): config.taylorDepth = 0 def __call__(self, **kwargs): # handle initial case id = None area = 1.0 if self.n == 0: center = self.config.initialDistribution() else: # select a mixture point try: point, area = self.sample() center = getattr(point, self.activeField) id = point.id self.ids.append(id) except Exception, msg: traceback.print_exc(file=sys.stdout) center = self.config.initialDistribution() if self.config.passArea: return center, area else: return center def batch(self, m): self.ids = [] ret = [self() for i in xrange(m)] self.config.primaryPopulation = self.ids return ret def update(self, n, population): rerun = self.n == n self.n = n if hasattr(self.config, 'anneal') and not self.config.anneal: self.temp = 1.0 else: self.temp = log(n) if self.segment is None: self.segment = Segment.objects.get(name=self.config.segment) if not rerun: if hasattr(self.config.fitness, 'train'): self.config.fitness.train(self, n)
[docs]class ProportionalAnnealing(Annealing): def __init__(self, config): if not hasattr(config, 'taylorDepth'): config.taylorDepth = 10 super(ProportionalAnnealing, self).__init__(config) def sample(self): return Point.objects.sampleProportional(self.segment, self.temp, self.config) #print "sampled: ", ret.binary, ret.score #return ret def update(self, n, population): rerun = n == self.n super(ProportionalAnnealing, self).update(n, population) if not rerun and .5 * floor(2*self.temp) > self.config.taylorCenter: ScoreTree.objects.resetTaylor(self.segment, .5 * floor(2 *self.temp), self.config)
[docs]class TournamentAnnealing(Annealing): def sample(self): return Point.objects.sampleTournament(self.segment, self.temp, self.config)
class TournamentNonAnnealing(TournamentAnnealing): def update(self, n, population): super(TournamentNonAnnealing, self).update(n, population) # now the population serves as the starting point self.temp = 1.0 class TournamentAnnealingSecondary(Annealing): def sample(self): if self.index >= len(self.config.primaryPopulation): self.index = 0 lastId = self.config.primaryPopulation[self.index] self.index += 1 return Point.objects.sampleTournamentSecondary(self.segment, lastId, self.temp, self.config) def batch(self, m): ret = [self() for i in xrange(m)] return ret def update(self, n, population): super(TournamentAnnealingSecondary, self).update(n, population) # now the population serves as the starting point self.index = 0