Class: Wallace::Breeder

Inherits:
Object
  • Object
show all
Defined in:
lib/core/breeder.rb

Overview

The breeder is decoupled from the evolver, subpopulation and population models. This allows the breeder to be used in a number of different configurations, where one breeder is used per evolver, population or sub-population.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Breeder

Constructs a new breeder.

Arguments

  • opts, a hash of keyword options for this method. -> graph, the breeding graph for this breeder. -> elitism, the number (or fraction) of fittest individuals that should be carried over to the next generation. (default = 0). -> threads, the number of threads the breeding process is split across. (default = 1).



20
21
22
23
24
# File 'lib/core/breeder.rb', line 20

def initialize(opts = {})
  @elitism = opts[:elitism]
  @threads = opts[:threads] || 1
  @graphs = Array.new(@threads) { opts[:graph].clone }
end

Instance Attribute Details

#elitismObject (readonly)

Returns the value of attribute elitism.



8
9
10
# File 'lib/core/breeder.rb', line 8

def elitism
  @elitism
end

#graphObject (readonly)

Returns the value of attribute graph.



8
9
10
# File 'lib/core/breeder.rb', line 8

def graph
  @graph
end

#threadsObject (readonly)

Returns the value of attribute threads.



8
9
10
# File 'lib/core/breeder.rb', line 8

def threads
  @threads
end

Instance Method Details

#breed!(rng, subpopulation) ⇒ Object

Breeds the next generation of individuals for the given subpopulation.

Parameters:

  • rng, random number generation to use during breeding.

  • subpopulation, the target subpopulation.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/core/breeder.rb', line 31

def breed!(rng, subpopulation)

  # Prepare the candidate list for each input for all graphs.
  @graphs[0].inputs.each_index do |i|
    candidates = subpopulation.contents
    @graphs.each_index do |g|
      candidates = @graphs[g].inputs[i].prepare!(candidates, random: rng, processed: g > 0)
    end
  end

  # Create a temporary array for the new sub-population.
  size = subpopulation.contents.size
  buffer = Array.new(size)

  # Add the elite individuals to the end of the sub-population if elitism is enabled.
  elites = @elitism.nil? ? 0 : @elitism
  elites = elites.value * size if elites.is_a? Wallace::Fraction
  buffer[(size - elites)...size] = subpopulation.contents.nmin(elites)

  # Spread the breeding process across multiple threads.
  # using a separate breeding graph for each thread to ensure thread-safety.
  thread_size = (size/@threads.to_f).ceil
  (0...@threads).peach(@threads) do |t|
    range = t * thread_size
    range = range...([size, range + thread_size].min)

    @graphs[t].breed!(rng, buffer, range)
  end

  # Clean each breeding graph.
  @graphs.each { |g| g.clean! }

  # Swap the contents of the sub-population with the buffer.
  subpopulation.contents = buffer

end