New issue 6 by hrudstrom: elite does not reevaluate fitness
http://code.google.com/p/ecspy/issues/detail?id=6
When using fitness functions that are randomized for each generation, the
elite individual is not reevaluated with the fitness case of its offspring
when determining if the elite survives to the next generation.
This means that a solution can by chance get very convenient fitness case
and stay as elite even when a better solution is found but in a less
convenient fitness case.
I'd suggest we add an args key 'revealuate_elites', and reevaluate the
elites in the main loop
or we make a decorator for the replacer function that reevaluates the elite
before calling the main replacer.
wow, that is really particular... could you perhaps add a script where the
debugger is raised in such a case ( or just a print statement, whatever ).
when I look at:
http://code.google.com/p/ecspy/source/browse/trunk/ecspy/evaluators.py
I cannot see where the values of an elitist indiv. are cached?
There is a caching function here:
http://code.google.com/p/ecspy/source/browse/trunk/ecspy/contrib/utils.py (
memoized ) where I can imagine this situation. but by default, that strikes
me...
it happens in the replacers,
they takes the elite individuals from the last generation, wich has the
fitness from the previous fitness evaluation and simply adds it to the
offspring and sorts them. Somewhere the elites need to be reevaluated.
def generational_replacement(.....):
num_elites = args.setdefault('num_elites', 0)
off = list(offspring)
pop = list(population)
pop.sort(reverse=True)
off.extend(pop[:num_elites])
off.sort(reverse=True)
survivors = off[:len(population)]
return survivors
I see. that makes things a lot clearer...
Well, I'm going to do a little thread necromancy and revive this year-old
discussion. Did we ever come to any solution? My thinking is that this
might be too problem-specific to add to the library. If we're using an
evaluator that has a random element to it, then we probably don't want to
use elitism anyway (for the reasons that Henrik described). If we do want
to use elitism, then Henrik's point is well taken. We need to re-evaluate
before the replacements are chosen. This would mean calling the evaluation
function inside the replacer. Something similar to the following decorator
would probably do the trick:
def reevaluator(replacer):
def ecspy_replacer(random, population, parents, offspring, args):
num_elites = args.setdefault('num_elites', 0)
if num_elites > 0:
population.sort(reverse=True)
elites = population[:num_elites]
elite_fitnesses = args['_ec'].evaluator(elites, args)
args['_ec'].num_evaluations += num_elites
for e, f in zip(elites, elite_fitnesses):
e.fitness = f
for p in parents:
for e in elites:
if e.candidate == p.candidate:
p.fitness = e.fitness
population[:num_elites] = elites
return replacer(random, population, parents, offspring, args)
ecspy_replacer.__name__ = replacer.__name__
ecspy_replacer.__dict__ = replacer.__dict__
ecspy_replacer.__doc__ = replacer.__doc__
return ecspy_replacer
Anyone care to comment on a ridiculously old thread?
Comment #5 on issue 6 by aaron.lee.garrett: elite does not reevaluate
fitness
http://code.google.com/p/ecspy/issues/detail?id=6
(No comment was entered for this change.)