Source code for pyec.distribution.de
from numpy import *
from pyec.distribution.basic import PopulationDistribution, FixedCube, Gaussian
from pyec.config import Config, ConfigBuilder
[docs]class DifferentialEvolution(PopulationDistribution):
"""
Implements Differential Evolution (DE) as described by:
Storn, Ranier and Price, Kenneth. Differential Evolution -- A simple and efficient adaptive scheme for global optimization over continuous spaces. 1995.
See <http://en.wikipedia.org/wiki/Differential_evolution> for algorithm details.
See <http://www.hvass-labs.org/people/magnus/publications/pedersen10good-de.pdf> for a good discussion of parameter settings for DE.
Config parameters:
* CR -- crossover probability
* F -- the learning rate
* initialDistribution -- the initial distribution to generate the first population
* populationSize -- the population size
* center -- the center of the space
* scale -- the scale of the space
* dim -- the number of real dimensions in the space
"""
unsorted = True
def __init__(self, cfg):
super(DifferentialEvolution, self).__init__(cfg)
self.CR = self.config.crossoverProb
self.F = self.config.learningRate
self.initial = self.config.initialDistribution
initial = hasattr(self.initial, 'batch') and self.initial.batch(self.config.populationSize) or [self.initial() for i in xrange(self.config.populationSize)]
self.xs = zip(initial, [None for i in xrange(self.config.populationSize)])
@classmethod
def configurator(cls):
return DEConfigurator(cls)
def batch(self, popSize):
idx = 0
ys = []
for x,s in self.xs:
y = ones(self.config.dim)
if True:
i1 = idx
while i1 == idx:
i1 = random.randint(0,self.config.populationSize)
i2 = i1
while i1 == i2 or i2 == idx:
i2 = random.randint(0,self.config.populationSize)
i3 = i2
while i1 == i3 or i2 == i3 or i3 == idx:
i3 = random.randint(0,self.config.populationSize)
a, s1 = self.xs[i1]
b, s2 = self.xs[i2]
c, s3 = self.xs[i3]
d = random.randint(0, len(x))
y = copy(x)
idx2 = 0
for yi in y:
r = random.random_sample()
if idx2 == d or r < self.CR:
y[idx2] = a[idx2] + self.F * (b[idx2] - c[idx2])
idx2 += 1
ys.append(y)
idx += 1
return ys
def update(self, generation, population):
idx = 0
# print [s for x,s in self.xs][:5]
for y,s2 in population:
x,s = self.xs[idx]
if s is None or s2 >= s:
self.xs[idx] = y,s2
idx += 1
[docs]class DEConfigurator(ConfigBuilder):
"""
A :class:`ConfigBuilder` object to create a :class:`DifferentialEvolution` instance.
Default parameters are CR = .2, F = .5; these can be changed
by editing the `cfg` property of this object.
"""
def __init__(self, *args):
super(DEConfigurator, self).__init__(DifferentialEvolution)
self.cfg.sort = False
self.cfg.crossoverProb = .2
self.cfg.learningRate = .5
def postConfigure(self, cfg):
if cfg.varInit is None:
cfg.initialDistribution = FixedCube(cfg)
else:
cfg.usePrior = False
cfg.initialDistribution = Gaussian(cfg)