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
list of critter in this population
Overall population fitness and novelty
Ordered list or hash of input neuron classes (all critters generated here shall have this)
Overall population fitness and novelty
Ordered list or hash of output neuron classes (all critters generated here shall have this)
Hash list of species lists
Public Class Methods
Create initial (ramdom) population of critters
# 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
Alalyze evaluation results.
# File lib/rubyneat/population.rb, line 74 def analyze! @critters.each { |critter| @controller.evaluator.analyze_for_fitness! critter } end
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
# File lib/rubyneat/population.rb, line 194 def dump_s to_s + "\npopulation:\n" + @critters.map{|crit| crit.dump_s }.join("\n") end
Called for each sequence.
# File lib/rubyneat/population.rb, line 69 def evaluate! @critters.each { |critter| critter.evaluate! } end
Call this after evaluation. Returns a newly-evolved population.
# File lib/rubyneat/population.rb, line 80 def evolve @controller.evolver.evolve self end
Express the entire population.
# File lib/rubyneat/population.rb, line 64 def express! @critters.each { |critter| critter.express! } end
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 the genes and neurons.
# File lib/rubyneat/population.rb, line 59 def mutate! @controller.evolver.mutate! self end
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
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
Find the best fit critter
# File lib/rubyneat/population.rb, line 217 def report_best_fit best_critter.phenotype.code end
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 on the best and worst species
# File lib/rubyneat/population.rb, line 209 def report_fitness_species { best: nil, worst: nil, } end
Find the worst fit critter
# File lib/rubyneat/population.rb, line 222 def report_worst_fit worst_critter.phenotype.code end