Xavier Nayrac

Rubyiste accro au TDD, serial blogger, apprenti data scientist, heureux utilisateur de Vim, accordéoniste.
Si vous vous sentez particulièrement généreux, suivez moi sur Twitter.

Les algorithmes génétiques démystifiés 46: Économie, la boucle principale

| Comments

Niveau : intermédiaire

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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.

Articles connexes

Commentaires