Class: NEAT::Population
- Defined in:
- lib/rubyneat/reporting.rb,
lib/rubyneat/population.rb
Overview
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.
Instance Attribute Summary collapse
-
#critters ⇒ Object
list of critter in this population.
-
#fitness ⇒ Object
readonly
Overall population fitness and novelty.
-
#hidden_neurons ⇒ Object
List of possible neuron classes for hidden neurons.
-
#input_neurons ⇒ Object
Ordered list or hash of input neuron classes (all critters generated here shall have this).
-
#novelty ⇒ Object
readonly
Overall population fitness and novelty.
-
#output_neurons ⇒ Object
Ordered list or hash of output neuron classes (all critters generated here shall have this).
-
#species ⇒ Object
readonly
Hash list of species lists.
-
#traits ⇒ Object
Returns the value of attribute traits.
Attributes inherited from NeatOb
Class Method Summary collapse
- .compactify!(parm) ⇒ Object
- .evaluate! ⇒ Object
-
.member?(crit) ⇒ Boolean
lists keyed by representative critter.
Instance Method Summary collapse
-
#analyze! ⇒ Object
Alalyze evaluation results.
-
#best_critter ⇒ Object
The “best critter” is the critter with the lowest (closet to zero) fitness rating.
-
#critter_hash ⇒ Object
TODO: we should probably provide a means to invalidate this cache.
- #dump_s ⇒ Object
-
#evaluate! ⇒ Object
Called for each sequence.
-
#evolve ⇒ Object
Call this after evaluation.
-
#express! ⇒ Object
Express the entire population.
-
#find_critters(*names) ⇒ Object
Retrive list of critters given from parameters given, names of critters.
-
#initialize(c, &block) ⇒ Population
constructor
Create initial (ramdom) population of critters.
-
#initialize_for_recurrence! ⇒ Object
Make sure all critters are reset and prepared for recurrent network evaluation.
-
#mutate! ⇒ Object
Mutate the genes and neurons.
-
#report ⇒ Object
Generate a report on the state of this population.
-
#report_best_fit ⇒ Object
Find the best fit critter.
-
#report_critters ⇒ Object
Create a hash of critter names and fitness values.
-
#report_fitness ⇒ Object
report on many fitness metrics.
-
#report_fitness_species ⇒ Object
report on the best and worst species.
-
#report_worst_fit ⇒ Object
Find the worst fit critter.
-
#speciate! ⇒ Object
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.
-
#worst_critter ⇒ Object
The “worst critter” is the critter with the highest (away from zero) fitness rating.
Methods inherited from NeatOb
Constructor Details
#initialize(c, &block) ⇒ Population
Create initial (ramdom) population of critters
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# 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 |
Instance Attribute Details
#critters ⇒ Object
list of critter in this population
30 31 32 |
# File 'lib/rubyneat/population.rb', line 30 def critters @critters end |
#fitness ⇒ Object (readonly)
Overall population fitness and novelty
33 34 35 |
# File 'lib/rubyneat/population.rb', line 33 def fitness @fitness end |
#hidden_neurons ⇒ Object
List of possible neuron classes for hidden neurons.
21 22 23 |
# File 'lib/rubyneat/population.rb', line 21 def hidden_neurons @hidden_neurons end |
#input_neurons ⇒ Object
Ordered list or hash of input neuron classes (all critters generated here shall have this)
18 19 20 |
# File 'lib/rubyneat/population.rb', line 18 def input_neurons @input_neurons end |
#novelty ⇒ Object (readonly)
Overall population fitness and novelty
33 34 35 |
# File 'lib/rubyneat/population.rb', line 33 def novelty @novelty end |
#output_neurons ⇒ Object
Ordered list or hash of output neuron classes (all critters generated here shall have this)
25 26 27 |
# File 'lib/rubyneat/population.rb', line 25 def output_neurons @output_neurons end |
#species ⇒ Object (readonly)
Hash list of species lists
36 37 38 |
# File 'lib/rubyneat/population.rb', line 36 def species @species end |
#traits ⇒ Object
Returns the value of attribute traits.
27 28 29 |
# File 'lib/rubyneat/population.rb', line 27 def traits @traits end |
Class Method Details
.compactify!(parm) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/rubyneat/population.rb', line 108 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 |
.evaluate! ⇒ Object
102 103 104 105 106 |
# File 'lib/rubyneat/population.rb', line 102 def @species.evaluate! self.each do |k, sp| sp.fitness = sp.map{|crit| crit.fitness}.reduce{|a,b| a+b} / sp.size end end |
.member?(crit) ⇒ Boolean
lists keyed by representative critter
98 99 100 |
# File 'lib/rubyneat/population.rb', line 98 def @species.member?(crit) super.member?(crit) or self.map{|k, li| li.member? crit}.reduce{|t1, t2| t1 or t2 } end |
Instance Method Details
#analyze! ⇒ Object
Alalyze evaluation results.
80 81 82 |
# File 'lib/rubyneat/population.rb', line 80 def analyze! @critters.each { |critter| @controller.evaluator.analyze_for_fitness! critter } end |
#best_critter ⇒ Object
The “best critter” is the critter with the lowest (closet to zero) fitness rating. TODO: DRY up best_critter and worst_critter
172 173 174 175 176 177 178 |
# 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 |
#critter_hash ⇒ Object
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.
72 73 74 |
# File 'lib/rubyneat/reporting.rb', line 72 def critter_hash @critter_hash ||= critters.inject({}){|memo, crit| memo[crit.name]=crit; memo} end |
#dump_s ⇒ Object
190 191 192 |
# File 'lib/rubyneat/population.rb', line 190 def dump_s to_s + "\npopulation:\n" + @critters.map{|crit| crit.dump_s }.join("\n") end |
#evaluate! ⇒ Object
Called for each sequence.
75 76 77 |
# File 'lib/rubyneat/population.rb', line 75 def evaluate! @critters.each { |critter| critter.evaluate! } end |
#evolve ⇒ Object
Call this after evaluation. Returns a newly-evolved population.
86 87 88 |
# File 'lib/rubyneat/population.rb', line 86 def evolve @controller.evolver.evolve self end |
#express! ⇒ Object
Express the entire population.
70 71 72 |
# File 'lib/rubyneat/population.rb', line 70 def express! @critters.each { |critter| critter.express! } end |
#find_critters(*names) ⇒ Object
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.
79 80 81 |
# File 'lib/rubyneat/reporting.rb', line 79 def find_critters(*names) names.map{|name| critter_hash[name.to_sym]} end |
#initialize_for_recurrence! ⇒ Object
Make sure all critters are reset and prepared for recurrent network evaluation.
60 61 62 |
# File 'lib/rubyneat/population.rb', line 60 def initialize_for_recurrence! @critters.each {|crit| crit.initialize_neurons!} end |
#mutate! ⇒ Object
Mutate the genes and neurons.
65 66 67 |
# File 'lib/rubyneat/population.rb', line 65 def mutate! @controller.evolver.mutate! self end |
#report ⇒ Object
Generate a report on the state of this population.
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# 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 |
#report_best_fit ⇒ Object
Find the best fit critter
39 40 41 |
# File 'lib/rubyneat/reporting.rb', line 39 def report_best_fit best_critter.phenotype.code end |
#report_critters ⇒ Object
Create a hash of critter names and fitness values
49 50 51 |
# File 'lib/rubyneat/reporting.rb', line 49 def report_critters critters.inject({}){|memo, critter| memo[critter.name] = critter.fitness; memo } end |
#report_fitness ⇒ Object
report on many fitness metrics
22 23 24 25 26 27 28 |
# 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_fitness_species ⇒ Object
report on the best and worst species
31 32 33 34 35 36 |
# File 'lib/rubyneat/reporting.rb', line 31 def report_fitness_species { best: nil, worst: nil, } end |
#report_worst_fit ⇒ Object
Find the worst fit critter
44 45 46 |
# File 'lib/rubyneat/reporting.rb', line 44 def report_worst_fit worst_critter.phenotype.code end |
#speciate! ⇒ Object
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
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# 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 |
#worst_critter ⇒ Object
The “worst critter” is the critter with the highest (away from zero) fitness rating.
182 183 184 185 186 187 188 |
# 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 |