Class: Population

Inherits:
Array
  • Object
show all
Defined in:
lib/charlie/population.rb

Overview

The population class represents an array of genotypes. Create an instance of this, and call one of the evolve functions to run the genetic algorithm.

Constant Summary collapse

DEFAULT_MAX_GENS =
100
DEFAULT_POP_SIZE =
20

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Array

#at_rand, #average, #dot_product, #find_index, #map_with_index, #rand_index, #shuffle, #shuffle!, #stats, #stddev, #swap_element_at_index!, #to_table

Constructor Details

#initialize(genotype_class, population_size = DEFAULT_POP_SIZE) ⇒ Population

Returns a new instance of Population.



10
11
12
13
# File 'lib/charlie/population.rb', line 10

def initialize(genotype_class,population_size=DEFAULT_POP_SIZE)
  @genotype_class = genotype_class
  replace Array.new(population_size){ genotype_class.new } 
end

Instance Attribute Details

#genotype_classObject (readonly)

Returns the value of attribute genotype_class.



9
10
11
# File 'lib/charlie/population.rb', line 9

def genotype_class
  @genotype_class
end

Class Method Details

.evolve_multiple(genotype_class, population_size = DEFAULT_POP_SIZE, n_runs = 25, generations = DEFAULT_MAX_GENS) ⇒ Object

Effectively runs Population#evolve_block n_runs times. Returns the entire population of all results (n_runs * population_size elements)



85
86
87
88
89
90
# File 'lib/charlie/population.rb', line 85

def self.evolve_multiple(genotype_class,population_size=DEFAULT_POP_SIZE,
                         n_runs=25,
                         generations=DEFAULT_MAX_GENS)
  r = evolve_multiple_until_population(genotype_class,population_size, n_runs, generations, 10000) {|pop| false }
  r.first
end

.evolve_multiple_until_best(*args, &b) ⇒ Object Also known as: evolve_multiple_until

Effectively runs Population#evolve_until_best multiple times.

  • See Population.evolve_multiple_until_population for arguments

Aliased also as Population.evolve_multiple_until.



96
97
98
# File 'lib/charlie/population.rb', line 96

def self.evolve_multiple_until_best(*args,&b)
  evolve_multiple_until_population(*args) {|pop| b.call(pop.max) }
end

.evolve_multiple_until_population(genotype_class, population_size = DEFAULT_POP_SIZE, max_tries = 25, generations = DEFAULT_MAX_GENS, check_every = 10) ⇒ Object

Runs Population#evolve_until_population multiple times.

  • genotype_class,population_size are arguments for Population.new

  • max_tries is the maximum number of restarts.

  • Returns [population, generations needed] on success where population is the population of the successful run.

  • Returns [population_all, nil] on failure, where population_all is the combined population of all runs.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/charlie/population.rb', line 105

def self.evolve_multiple_until_population(genotype_class,population_size=DEFAULT_POP_SIZE,
                                          max_tries=25,
                                          generations=DEFAULT_MAX_GENS,check_every=10)
  tot_gens = 0
  all_pop = []
  max_tries.times{
    pop, gens = Population.new(genotype_class,population_size).evolve_until_population(generations,check_every){|p|
      yield(p)
    }
    all_pop  += pop
    tot_gens += gens || generations
    if gens
      return [pop, tot_gens]
    end
  }
  [all_pop, nil]
end

Instance Method Details

#evolve_block(max_generations = DEFAULT_MAX_GENS) {|_self, 0| ... } ⇒ Object

Yields the population and the generation number to block for each generation at a maximum of max_generations times.

Yields:

  • (_self, 0)

Yield Parameters:

  • _self (Population)

    the object that the method was called on



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/charlie/population.rb', line 16

def evolve_block(max_generations=DEFAULT_MAX_GENS)
  yield self, 0
  (max_generations || DEFAULT_MAX_GENS).times {|generation|
    self.population = @genotype_class.next_generation(self){|*parents|
      ch = [*@genotype_class.cross(*parents)]
      ch.each{|c| c.mutate! }
      ch
    }
    yield self, generation+1
  }
  self
end

#evolve_on_console(generations = DEFAULT_MAX_GENS) ⇒ Object Also known as: evolve

Runs the genetic algorithm with some stats on the console. Returns the population sorted by fitness.



37
38
39
40
41
42
43
44
45
46
# File 'lib/charlie/population.rb', line 37

def evolve_on_console(generations=DEFAULT_MAX_GENS)
  puts "Generation\tBest Fitness\t\tBest Individual"
  evolve_block(generations) {|p,g|
    best = p.max
    puts "#{g}\t\t#{best.fitness}\t\t#{best.to_s}"
  }
  self.population = self.sort_by{|x|x.fitness}
  puts "Finished: Best fitness = #{self[-1].fitness}"
  self
end

#evolve_silent(generations = DEFAULT_MAX_GENS) ⇒ Object

Runs the genetic algorithm without any output. Returns the population sorted by fitness (unsorted for co-evolution).



30
31
32
33
34
# File 'lib/charlie/population.rb', line 30

def evolve_silent(generations=DEFAULT_MAX_GENS)
  evolve_block(generations){}
  sort_by!{|x|x.fitness} rescue nil
  self
end

#evolve_until_best(generations = DEFAULT_MAX_GENS, check_every = 10) ⇒ Object Also known as: evolve_until

breaks if the block (which is passed the best individual each “check_every” generations) returns true. returns an array [population, generations needed]. generations needed==nil for no convergence.



64
65
66
67
68
69
70
71
72
73
# File 'lib/charlie/population.rb', line 64

def evolve_until_best(generations=DEFAULT_MAX_GENS,check_every=10)
  tot_gens = nil
  evolve_block(generations)  {|p,g|
    if (g % check_every).zero? && yield(p.max)
      tot_gens = g
      break 
    end
  }
  [self, tot_gens]
end

#evolve_until_population(generations = DEFAULT_MAX_GENS, check_every = 10) ⇒ Object

breaks if the block (which is passed the population each “check_every” generations) returns true. returns an array [population, generations needed]. generations needed==nil for no convergence.



51
52
53
54
55
56
57
58
59
60
# File 'lib/charlie/population.rb', line 51

def evolve_until_population(generations=DEFAULT_MAX_GENS,check_every=10)
  tot_gens = nil
  evolve_block(generations) {|p,g|
    if (g % check_every).zero? && yield(p)
      tot_gens = g
      break
    end
  }
  [self, tot_gens]
end

#populationObject

backwards compatibility, returns self



78
# File 'lib/charlie/population.rb', line 78

def population; self; end