Les algorithmes génétiques démystifiés 46: Économie, la boucle principale
Après le calcul du score
d’un individu, voici maintenant le coeur du programme, la classe
GeneticAlgorithm
.
Cette classe est batie sur le même modèle que pour les problèmes vus précédement, je ne vais donc pas la commenter en détails. Voici d’abord les méthodes publiques:
class GeneticAlgorithm
def initialize(generations:, population:, capacity:, mutation_rate:, items:)
@generations = generations
@population = population
@capacity = capacity
@mutation_rate = mutation_rate
@items = items
@crossover = Crossover.new chromosome_size: items.size,
mutation_rate: mutation_rate,
items: items
@best_ever = nil
end
def run
@generations.times do |generation|
Evaluator.new(capacity: @capacity, population: @population,
items: @items).evaluate!
find_best_ever(generation)
next_generation
end
puts IndividualFormatter.display_best_ever individual: @best_ever,
items: @items
end
# ...
end
L’initialisation est des plus basiques. Quant à la méthode run
, elle
introduit une nouvelle classe : IndividualFormatter
. Cette classe sera
discutée en détail dans le prochain article.
Maintenant les méthodes privées:
class GeneticAlgorithm
# ...
private
def find_best_ever(generation)
best = @population.best
@best_ever = best if best > @best_ever
puts IndividualFormatter.display individual: @best_ever,
generation: generation,
items: @items,
capacity: @capacity
end
def next_generation
@population.sort_by! {|i| i.score}
elite = @population.pop(4)
pool = MatingPool.new(@population)
population_size = @population.size
@population.clear
population_size.times do
@population << @crossover.two_point(pool.random, pool.random)
end
@population.concat elite
end
end
find_best_ever
va trouver le meilleur individu à un moment précis, toutes
générations confondues et va afficher cet individu via IndividualFormatter
(Je sais, c’est mal, cette méthode fait deux choses…).
Quant à la méthode next_generation
, c’est la même que pour
le problème précédent.
À demain.