class NEAT::Population

Population of NEAT Critters.

The Population 
In ourselves we have the pool of neurons the critters all use.
the pool of neurons are indirects, of course, as during phenotype
expression, all the phenotypes shall be created individually.

Attributes

critters[RW]

list of critter in this population

fitness[R]

Overall population fitness and novelty

hidden_neurons[RW]

List of possible neuron classes for hidden neurons.

input_neurons[RW]

Ordered list or hash of input neuron classes (all critters generated here shall have this)

novelty[R]

Overall population fitness and novelty

output_neurons[RW]

Ordered list or hash of output neuron classes (all critters generated here shall have this)

species[R]

Hash list of species lists

traits[RW]

Public Class Methods

new(c, &block) click to toggle source

Create initial (ramdom) population of critters

Calls superclass method
# File lib/rubyneat/population.rb, line 37
def initialize(c, &block)
  super
  @input_neurons = c.neural_inputs.clone
  @output_neurons = c.neural_outputs.clone
  @hidden_neurons = unless c.neural_hidden.nil?
                      c.neural_hidden
                    else
                      c.neuron_catalog.keep_if {|n| not n.input?}
                    end
  @critters = (0 ... c.parms.start_population_size || c.parms.population_size).map do
    Critter.new(self)
  end
  block.(self) unless block.nil?
end

Public Instance Methods

analyze!() click to toggle source

Alalyze evaluation results.

# File lib/rubyneat/population.rb, line 74
def analyze!
   @critters.each { |critter| @controller.evaluator.analyze_for_fitness! critter }
end
best_critter() click to toggle source

The “best critter” is the critter with the lowest (closet to zero) fitness rating.

# File lib/rubyneat/population.rb, line 176
def best_critter
  unless @controller.compare_func.nil?
    @critters.min {|a, b| @controller.compare_func.(a.fitness, b.fitness) }
  else
    @critters.min {|a, b| a.fitness <=> b.fitness}
  end
end
dump_s() click to toggle source
# File lib/rubyneat/population.rb, line 194
def dump_s
  to_s + "\npopulation:\n" + @critters.map{|crit| crit.dump_s }.join("\n")
end
evaluate!() click to toggle source

Called for each sequence.

# File lib/rubyneat/population.rb, line 69
def evaluate!
   @critters.each { |critter| critter.evaluate! }
end
evolve() click to toggle source

Call this after evaluation. Returns a newly-evolved population.

# File lib/rubyneat/population.rb, line 80
def evolve
  @controller.evolver.evolve self
end
express!() click to toggle source

Express the entire population.

# File lib/rubyneat/population.rb, line 64
def express!
   @critters.each { |critter| critter.express! }
end
initialize_for_recurrence!() click to toggle source

Make sure all critters are reset and prepared for recurrent network evaluation.

# File lib/rubyneat/population.rb, line 54
def initialize_for_recurrence!
  @critters.each {|crit| crit.initialize_neurons!}
end
mutate!() click to toggle source

Mutate the genes and neurons.

# File lib/rubyneat/population.rb, line 59
def mutate!
  @controller.evolver.mutate! self
end
report() click to toggle source

Generate a report on the state of this population.

# File lib/rubyneat/population.rb, line 165
def report
  {
      fitness:         report_fitness,
      fitness_species: report_fitness_species,
      best_critter:    report_best_fit,
      worst_critter:   report_worst_fit,
  }
end
speciate!() click to toggle source
Group critters into species
Note that the @species objects
have useful singleton methods:
  • @species.member? – checks all of the lists for membership, not just the hash

  • @species.fitness – fitness of the entire species

# File lib/rubyneat/population.rb, line 89
def speciate!
  # We blow away existing species and create our own member? function
  @species = {} # lists keyed by representative critter
  def @species.member?(crit)
    super.member?(crit) or self.map{|k, li| li.member? crit}.reduce{|t1, t2| t1 or t2 }
  end

  def @species.evaluate!
    self.each do |k, sp|
      sp.fitness = sp.map{|crit| crit.fitness}.reduce{|a,b| a+b} / sp.size
    end
  end

  def @species.compactify!(parm)
    mutt = self[:mutt] = self.map { |k, splist| [k, splist]}.reject {|k, splist|
      splist.size >= parm.smallest_species
    }.map { |k, splist|
      self.delete k
      splist
    }.flatten

    # FIXME this code is not dry!!!!
    def mutt.fitness=(fit)
      @fitness = fit
    end

    def mutt.fitness
      @fitness
    end

    self.delete :mutt if self[:mutt].empty?
  end

  # Some convience parms
  parm = @controller.parms

  # And so now we iterate...
  @critters.each do |crit|
    wearein = false
    @species.each do |ck, list|
      delta = crit.compare(ck)
      #log.debug { "delta for #{crit} and #{ck} is #{delta}" }
      if delta < parm.compatibility_threshold
        list << crit
        wearein = true
        break
      end
    end

    # New species?
    unless wearein
      @species[crit] = species = [crit]
      def species.fitness=(fit)
        @fitness = fit
      end
      def species.fitness
        @fitness
      end
    end
  end

  # Compactify the species if less than smallest_species
  @species.compactify! parm

  # And now we evaluate all species for fitness...
  @species.evaluate!

  # Dump for debugging reasons
  @species.each do |k, sp|
    log.debug ">> Species #{k} has #{sp.size} members with a #{sp.fitness} fitness"
  end

end
worst_critter() click to toggle source

The “worst critter” is the critter with the highest (away from zero) fitness rating.

# File lib/rubyneat/population.rb, line 186
def worst_critter
  unless @controller.compare_func.nil?
    @critters.max {|a, b| @controller.compare_func.(a.fitness, b.fitness) }
  else
    @critters.max {|a, b| a.fitness <=> b.fitness}
  end
end

Protected Instance Methods

report_best_fit() click to toggle source

Find the best fit critter

# File lib/rubyneat/population.rb, line 217
def report_best_fit
  best_critter.phenotype.code
end
report_fitness() click to toggle source

report on many fitness metrics

# File lib/rubyneat/population.rb, line 200
def report_fitness
  {
      overall: @critters.map{|critter| critter.fitness}.reduce{|m, f| m + f} / @critters.size,
      best: best_critter.fitness,
      worst: worst_critter.fitness,
  }
end
report_fitness_species() click to toggle source

report on the best and worst species

# File lib/rubyneat/population.rb, line 209
def report_fitness_species
  {
    best: nil,
    worst: nil,
  }
end
report_worst_fit() click to toggle source

Find the worst fit critter

# File lib/rubyneat/population.rb, line 222
def report_worst_fit
  worst_critter.phenotype.code
end