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.
Population
Reporting¶ ↑
The tangenial reporting needs for the Population module are extracted here simply because they do not directly relate to the operations of the Population.
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 42 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 80 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. TODO: DRY up best_critter
and worst_critter
# File lib/rubyneat/population.rb, line 172 def best_critter unless @controller.compare_func.empty? @critters.min {|a, b| @controller.compare_func_hook(a.fitness, b.fitness) } else @critters.min {|a, b| a.fitness <=> b.fitness} end end
TODO: we should probably provide a means to invalidate this cache. TODO: but in most reasonable use cases this would not be called until TODO: after all the critters have been created.
# File lib/rubyneat/reporting.rb, line 72 def critter_hash @critter_hash ||= critters.inject({}){|memo, crit| memo[crit.name]=crit; memo} end
# File lib/rubyneat/population.rb, line 190 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 75 def evaluate! @critters.each { |critter| critter.evaluate! } end
Call this after evaluation. Returns a newly-evolved population.
# File lib/rubyneat/population.rb, line 86 def evolve @controller.evolver.evolve self end
Express the entire population.
# File lib/rubyneat/population.rb, line 70 def express! @critters.each { |critter| critter.express! } end
Retrive list of critters given from parameters given, names of critters. Return the results in an array. Names given must exist. Can be either strings or symbols or something that can be reduced to symbols, at least.
# File lib/rubyneat/reporting.rb, line 79 def find_critters(*names) names.map{|name| critter_hash[name.to_sym]} end
Make sure all critters are reset and prepared for recurrent network evaluation.
# File lib/rubyneat/population.rb, line 60 def initialize_for_recurrence! @critters.each {|crit| crit.initialize_neurons!} end
Mutate the genes and neurons.
# File lib/rubyneat/population.rb, line 65 def mutate! @controller.evolver.mutate! self end
Generate a report on the state of this population.¶ ↑
# File lib/rubyneat/reporting.rb, line 55 def report [ self, { generation: generation, fitness: report_fitness, fitness_species: report_fitness_species, best_critter: report_best_fit, worst_critter: report_worst_fit, all_critters: report_critters, } ] end
Find the best fit critter
# File lib/rubyneat/reporting.rb, line 39 def report_best_fit best_critter.phenotype.code end
Create a hash of critter names and fitness values
# File lib/rubyneat/reporting.rb, line 49 def report_critters critters.inject({}){|memo, critter| memo[critter.name] = critter.fitness; memo } end
report on many fitness metrics
# File lib/rubyneat/reporting.rb, line 22 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/reporting.rb, line 31 def report_fitness_species { best: nil, worst: nil, } end
Find the worst fit critter
# File lib/rubyneat/reporting.rb, line 44 def report_worst_fit worst_critter.phenotype.code 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 95 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 182 def worst_critter unless @controller.compare_func.empty? @critters.max {|a, b| @controller.compare_func_hook(a.fitness, b.fitness) } else @critters.max {|a, b| a.fitness <=> b.fitness} end end