def fitness_function(individual, FITNESS_FUNCTIONS):
"""
individual is your compiled solution
FITNESS_FUNCTIONS is a list of functions, like [sum, compute_something, another_function]
P.S., Not [sum(), compute_something(), another_function()], but just the function as it'll be invoked later
In my setup, all my objectives take the same set of parameters/metrics, even if they don't require it.
"""
fitnesses = []
"""
Compute the metrics you need, independently of you fitness function
"""
metric1 = compute_metric1(individual)
metric2 = compute_metric2(individual)
metric3 = compute_metric3(individual)
metrics = [ metric1, metric2, metric3 ]
for f in FITNESS_FUNCTIONS:
# Again, assuming that all your functions take the same parameters
fitnesses.append( f(*metrics) )
# If there's something you don't like about the solution , return ([0.0] * len(fitnesses)) as the fitness score, making the lowest possible scoring fitness function
# You can check at the individual level or the fitness level
fitnesses = handle_constraints_over_individual(individual) # If it doesn't look like what I want, return [0.0, 0.0, .... ]
fitnesses = handle_constraints_over_fitnesses(fitnesses) # If the fitness has something I don't like, , return [0.0, 0.0, .... ]
return tuple(fitnesses)
I still think it would be more elegant to use the penalty decorator, but maybe there's a limitation there?