To do fitness sharing, you would have to define your own shared fitness function that depends on the entire population.
Assuming you already defined a fitness
function, you could do the following:
from scipy.spatial import distance_matrix
def sharing(distance, sigma, alpha):
res = 0
if distance<sigma:
res += 1 - (distance/sigma)**alpha
return res
def shared_fitness(individual, population, sigma, alpha):
num = fitness(individual)[0]
dists = distance_matrix([individual], population)[0]
tmp = [sharing(d, sigma, alpha) for d in dists]
den = sum(tmp)
return num/den,
This shared fitness will favor individuals with fewer neighbors. sigma
is the radius in which neighbors will penalize an individual's shared fitness. If sigma
is bigger, then your niches will be further away, and you risk missing a local maximum. If sigma
is smaller, you need a larger population, and your algorithm will take longer to run. alpha
indicates how strong the penalization for nearby neighbors is.
This shared fitness can then be registered in your toolbox like a regular fitness.
population = toolbox.population()
toolbox.register('evaluate', shared_fitness, population=population, sigma=0.1, alpha=1.)
After that, you can use a standard algorithm like $\mu + \lambda$, that will select offspring based on their fitness, to get niching.