rubyneat 0.3.5.alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. checksums.yaml +7 -0
  2. data/.directory +4 -0
  3. data/.gitignore.orig +20 -0
  4. data/.idea/.name +1 -0
  5. data/.idea/.rakeTasks +7 -0
  6. data/.idea/dictionaries/trader.xml +3 -0
  7. data/.idea/encodings.xml +5 -0
  8. data/.idea/misc.xml +5 -0
  9. data/.idea/modules.xml +9 -0
  10. data/.idea/rubyneat.iml +197 -0
  11. data/.idea/runConfigurations/invpend_neat.xml +26 -0
  12. data/.idea/runConfigurations/sigdebug_neat.xml +24 -0
  13. data/.idea/runConfigurations/xor_neat.xml +26 -0
  14. data/.idea/runConfigurations/xordebug_neat.xml +24 -0
  15. data/.idea/runConfigurations/xorsin_neat.xml +24 -0
  16. data/.idea/scopes/scope_settings.xml +5 -0
  17. data/.idea/vcs.xml +7 -0
  18. data/.idea/workspace.xml +1124 -0
  19. data/.semver +5 -0
  20. data/.yardoc/checksums +11 -0
  21. data/.yardoc/object_types +0 -0
  22. data/.yardoc/objects/root.dat +0 -0
  23. data/.yardoc/proxy_types +0 -0
  24. data/Gemfile +32 -0
  25. data/Gemfile.lock +135 -0
  26. data/Gemfile.lock.orig +147 -0
  27. data/Guardfile +8 -0
  28. data/Rakefile +61 -0
  29. data/bin/neat +83 -0
  30. data/config/application.rb +5 -0
  31. data/doc/ControllerPoint.html +125 -0
  32. data/doc/CuteA.html +286 -0
  33. data/doc/CuteB.html +297 -0
  34. data/doc/DSL.html +883 -0
  35. data/doc/NEAT/BasicNeuronTypes/BiasNeuron.html +518 -0
  36. data/doc/NEAT/BasicNeuronTypes/CosineNeuron.html +274 -0
  37. data/doc/NEAT/BasicNeuronTypes/InputNeuron.html +366 -0
  38. data/doc/NEAT/BasicNeuronTypes/SigmoidNeuron.html +275 -0
  39. data/doc/NEAT/BasicNeuronTypes/SineNeuron.html +274 -0
  40. data/doc/NEAT/BasicNeuronTypes/TanhNeuron.html +274 -0
  41. data/doc/NEAT/BasicNeuronTypes.html +136 -0
  42. data/doc/NEAT/Controller/NeatSettings.html +3985 -0
  43. data/doc/NEAT/Controller.html +2490 -0
  44. data/doc/NEAT/Critter/Genotype/Gene.html +979 -0
  45. data/doc/NEAT/Critter/Genotype.html +1601 -0
  46. data/doc/NEAT/Critter/Phenotype.html +603 -0
  47. data/doc/NEAT/Critter.html +1037 -0
  48. data/doc/NEAT/DSL.html +1255 -0
  49. data/doc/NEAT/Evaluator.html +420 -0
  50. data/doc/NEAT/Evolver/CritterOp.html +551 -0
  51. data/doc/NEAT/Evolver.html +602 -0
  52. data/doc/NEAT/Expressor.html +327 -0
  53. data/doc/NEAT/Graph/DependencyResolver.html +478 -0
  54. data/doc/NEAT/Graph/GraphException.html +123 -0
  55. data/doc/NEAT/Graph.html +402 -0
  56. data/doc/NEAT/NeatException.html +123 -0
  57. data/doc/NEAT/NeatOb.html +567 -0
  58. data/doc/NEAT/Neuron.html +1067 -0
  59. data/doc/NEAT/Operator.html +162 -0
  60. data/doc/NEAT/Population.html +1961 -0
  61. data/doc/NEAT/Trait.html +169 -0
  62. data/doc/NEAT.html +588 -0
  63. data/doc/_index.html +373 -0
  64. data/doc/class_list.html +54 -0
  65. data/doc/css/common.css +1 -0
  66. data/doc/css/full_list.css +57 -0
  67. data/doc/css/style.css +339 -0
  68. data/doc/file_list.html +53 -0
  69. data/doc/frames.html +26 -0
  70. data/doc/index.html +373 -0
  71. data/doc/js/app.js +219 -0
  72. data/doc/js/full_list.js +178 -0
  73. data/doc/js/jquery.js +4 -0
  74. data/doc/method_list.html +1415 -0
  75. data/doc/top-level-namespace.html +164 -0
  76. data/foo/foo_aquarium_example.rb +38 -0
  77. data/foo/foo_gosu.rb +99 -0
  78. data/foo/foo_rubygoo.rb +104 -0
  79. data/foo/foo_sdl.rb +34 -0
  80. data/foo/icon.png +0 -0
  81. data/lib/rubyneat/critter.rb +374 -0
  82. data/lib/rubyneat/default_neat.rb +10 -0
  83. data/lib/rubyneat/dsl.rb +130 -0
  84. data/lib/rubyneat/evaluator.rb +51 -0
  85. data/lib/rubyneat/evolver.rb +315 -0
  86. data/lib/rubyneat/expressor.rb +110 -0
  87. data/lib/rubyneat/graph.rb +95 -0
  88. data/lib/rubyneat/neuron.rb +152 -0
  89. data/lib/rubyneat/population.rb +227 -0
  90. data/lib/rubyneat/rubyneat.rb +429 -0
  91. data/lib/rubyneat.rb +8 -0
  92. data/neater/invpend_neat.rb +150 -0
  93. data/neater/rnlib/inverted_pendulum.rb +380 -0
  94. data/neater/rnlib/xor.rb +10 -0
  95. data/neater/sigdebug_neat.rb +136 -0
  96. data/neater/xor_neat.rb +137 -0
  97. data/neater/xoranalog_neat.rb +138 -0
  98. data/neater/xorsin_neat.rb +143 -0
  99. data/projectFilesBackup/.idea/rubyneat.iml +180 -0
  100. data/public/.directory +4 -0
  101. data/public/background.png +0 -0
  102. data/public/background.xcf +0 -0
  103. data/public/cart.png +0 -0
  104. data/public/cart.xcf +0 -0
  105. data/public/metalpoles_molton_ball_l.jpg +0 -0
  106. data/public/old_background.png +0 -0
  107. data/public/pointer.png +0 -0
  108. data/public/pointer.xcf +0 -0
  109. data/public/pole.kra +0 -0
  110. data/public/pole.png +0 -0
  111. data/public/pole.xcf +0 -0
  112. data/public/wheel-of-year-stone-DD-131-WOYS.jpg +0 -0
  113. data/public/wheel.png +0 -0
  114. data/public/wheel.xcf +0 -0
  115. data/public/wood-planks-texture.jpg +0 -0
  116. data/rdoc/ControllerPoint.html +116 -0
  117. data/rdoc/CuteA.html +177 -0
  118. data/rdoc/CuteB.html +178 -0
  119. data/rdoc/DSLSetup.html +177 -0
  120. data/rdoc/GameTestWindow.html +242 -0
  121. data/rdoc/GameWindow.html +292 -0
  122. data/rdoc/Gemfile.html +215 -0
  123. data/rdoc/Gemfile_lock.html +327 -0
  124. data/rdoc/GraphTest.html +210 -0
  125. data/rdoc/Guardfile.html +198 -0
  126. data/rdoc/InvertedPendulum/Cart.html +668 -0
  127. data/rdoc/InvertedPendulum/DSL.html +259 -0
  128. data/rdoc/InvertedPendulum/InvPendWindow.html +402 -0
  129. data/rdoc/InvertedPendulum.html +198 -0
  130. data/rdoc/Logger.html +98 -0
  131. data/rdoc/NEAT/BasicNeuronTypes/BiasNeuron.html +265 -0
  132. data/rdoc/NEAT/BasicNeuronTypes/CosineNeuron.html +162 -0
  133. data/rdoc/NEAT/BasicNeuronTypes/InputNeuron.html +206 -0
  134. data/rdoc/NEAT/BasicNeuronTypes/SigmoidNeuron.html +162 -0
  135. data/rdoc/NEAT/BasicNeuronTypes/SineNeuron.html +162 -0
  136. data/rdoc/NEAT/BasicNeuronTypes/TanhNeuron.html +161 -0
  137. data/rdoc/NEAT/BasicNeuronTypes.html +107 -0
  138. data/rdoc/NEAT/Controller/NeatSettings.html +880 -0
  139. data/rdoc/NEAT/Controller.html +729 -0
  140. data/rdoc/NEAT/Critter/Genotype/Gene.html +457 -0
  141. data/rdoc/NEAT/Critter/Genotype.html +735 -0
  142. data/rdoc/NEAT/Critter/Phenotype.html +330 -0
  143. data/rdoc/NEAT/Critter.html +489 -0
  144. data/rdoc/NEAT/DSL.html +729 -0
  145. data/rdoc/NEAT/Evaluator.html +256 -0
  146. data/rdoc/NEAT/Evolver/CritterOp.html +349 -0
  147. data/rdoc/NEAT/Evolver.html +891 -0
  148. data/rdoc/NEAT/Expressor.html +402 -0
  149. data/rdoc/NEAT/Graph/DependencyResolver.html +291 -0
  150. data/rdoc/NEAT/Graph/GraphException.html +105 -0
  151. data/rdoc/NEAT/Graph.html +263 -0
  152. data/rdoc/NEAT/NeatException.html +105 -0
  153. data/rdoc/NEAT/NeatOb.html +325 -0
  154. data/rdoc/NEAT/Neuron.html +481 -0
  155. data/rdoc/NEAT/Operator.html +109 -0
  156. data/rdoc/NEAT/Population.html +935 -0
  157. data/rdoc/NEAT/Trait.html +117 -0
  158. data/rdoc/NEAT.html +422 -0
  159. data/rdoc/Object.html +384 -0
  160. data/rdoc/Phi.html +98 -0
  161. data/rdoc/Player.html +383 -0
  162. data/rdoc/Rakefile.html +254 -0
  163. data/rdoc/RubyNEAT/Application.html +105 -0
  164. data/rdoc/RubyNEAT.html +98 -0
  165. data/rdoc/SDL/Event2.html +98 -0
  166. data/rdoc/SDL.html +98 -0
  167. data/rdoc/Vector.html +195 -0
  168. data/rdoc/created.rid +125 -0
  169. data/rdoc/doc/ControllerPoint_html.html +299 -0
  170. data/rdoc/doc/CuteA_html.html +438 -0
  171. data/rdoc/doc/CuteB_html.html +436 -0
  172. data/rdoc/doc/DSL_html.html +992 -0
  173. data/rdoc/doc/NEAT/BasicNeuronTypes/BiasNeuron_html.html +617 -0
  174. data/rdoc/doc/NEAT/BasicNeuronTypes/CosineNeuron_html.html +413 -0
  175. data/rdoc/doc/NEAT/BasicNeuronTypes/InputNeuron_html.html +498 -0
  176. data/rdoc/doc/NEAT/BasicNeuronTypes/SigmoidNeuron_html.html +413 -0
  177. data/rdoc/doc/NEAT/BasicNeuronTypes/SineNeuron_html.html +413 -0
  178. data/rdoc/doc/NEAT/BasicNeuronTypes/TanhNeuron_html.html +412 -0
  179. data/rdoc/doc/NEAT/BasicNeuronTypes_html.html +310 -0
  180. data/rdoc/doc/NEAT/Controller/NeatSettings_html.html +3324 -0
  181. data/rdoc/doc/NEAT/Controller_html.html +2212 -0
  182. data/rdoc/doc/NEAT/Critter/Genotype/Gene_html.html +997 -0
  183. data/rdoc/doc/NEAT/Critter/Genotype_html.html +1556 -0
  184. data/rdoc/doc/NEAT/Critter/Phenotype_html.html +687 -0
  185. data/rdoc/doc/NEAT/Critter_html.html +1037 -0
  186. data/rdoc/doc/NEAT/DSL_html.html +1349 -0
  187. data/rdoc/doc/NEAT/Evaluator_html.html +556 -0
  188. data/rdoc/doc/NEAT/Evolver/CritterOp_html.html +690 -0
  189. data/rdoc/doc/NEAT/Evolver_html.html +677 -0
  190. data/rdoc/doc/NEAT/Expressor_html.html +468 -0
  191. data/rdoc/doc/NEAT/Graph/DependencyResolver_html.html +598 -0
  192. data/rdoc/doc/NEAT/Graph/GraphException_html.html +299 -0
  193. data/rdoc/doc/NEAT/Graph_html.html +527 -0
  194. data/rdoc/doc/NEAT/NeatException_html.html +299 -0
  195. data/rdoc/doc/NEAT/NeatOb_html.html +671 -0
  196. data/rdoc/doc/NEAT/Neuron_html.html +1095 -0
  197. data/rdoc/doc/NEAT/Operator_html.html +337 -0
  198. data/rdoc/doc/NEAT/Population_html.html +1795 -0
  199. data/rdoc/doc/NEAT/Trait_html.html +344 -0
  200. data/rdoc/doc/NEAT_html.html +736 -0
  201. data/rdoc/doc/_index_html.html +559 -0
  202. data/rdoc/doc/class_list_html.html +369 -0
  203. data/rdoc/doc/css/common_css.html +188 -0
  204. data/rdoc/doc/css/full_list_css.html +243 -0
  205. data/rdoc/doc/css/style_css.html +530 -0
  206. data/rdoc/doc/file_list_html.html +240 -0
  207. data/rdoc/doc/frames_html.html +217 -0
  208. data/rdoc/doc/index_html.html +559 -0
  209. data/rdoc/doc/js/app_js.html +423 -0
  210. data/rdoc/doc/js/full_list_js.html +372 -0
  211. data/rdoc/doc/js/jquery_js.html +1536 -0
  212. data/rdoc/doc/method_list_html.html +1375 -0
  213. data/rdoc/doc/top-level-namespace_html.html +317 -0
  214. data/rdoc/fonts/Lato-Light.ttf +0 -0
  215. data/rdoc/fonts/Lato-LightItalic.ttf +0 -0
  216. data/rdoc/fonts/Lato-Regular.ttf +0 -0
  217. data/rdoc/fonts/Lato-RegularItalic.ttf +0 -0
  218. data/rdoc/fonts/SourceCodePro-Bold.ttf +0 -0
  219. data/rdoc/fonts/SourceCodePro-Regular.ttf +0 -0
  220. data/rdoc/fonts.css +167 -0
  221. data/rdoc/images/add.png +0 -0
  222. data/rdoc/images/arrow_up.png +0 -0
  223. data/rdoc/images/brick.png +0 -0
  224. data/rdoc/images/brick_link.png +0 -0
  225. data/rdoc/images/bug.png +0 -0
  226. data/rdoc/images/bullet_black.png +0 -0
  227. data/rdoc/images/bullet_toggle_minus.png +0 -0
  228. data/rdoc/images/bullet_toggle_plus.png +0 -0
  229. data/rdoc/images/date.png +0 -0
  230. data/rdoc/images/delete.png +0 -0
  231. data/rdoc/images/find.png +0 -0
  232. data/rdoc/images/loadingAnimation.gif +0 -0
  233. data/rdoc/images/macFFBgHack.png +0 -0
  234. data/rdoc/images/package.png +0 -0
  235. data/rdoc/images/page_green.png +0 -0
  236. data/rdoc/images/page_white_text.png +0 -0
  237. data/rdoc/images/page_white_width.png +0 -0
  238. data/rdoc/images/plugin.png +0 -0
  239. data/rdoc/images/ruby.png +0 -0
  240. data/rdoc/images/tag_blue.png +0 -0
  241. data/rdoc/images/tag_green.png +0 -0
  242. data/rdoc/images/transparent.png +0 -0
  243. data/rdoc/images/wrench.png +0 -0
  244. data/rdoc/images/wrench_orange.png +0 -0
  245. data/rdoc/images/zoom.png +0 -0
  246. data/rdoc/index.html +282 -0
  247. data/rdoc/js/darkfish.js +140 -0
  248. data/rdoc/js/jquery.js +18 -0
  249. data/rdoc/js/navigation.js +142 -0
  250. data/rdoc/js/search.js +109 -0
  251. data/rdoc/js/search_index.js +1 -0
  252. data/rdoc/js/searcher.js +228 -0
  253. data/rdoc/rdoc.css +580 -0
  254. data/rdoc/rubyneat_gemspec.html +387 -0
  255. data/rdoc/table_of_contents.html +2502 -0
  256. data/rdoc/xordebug_log.html +170598 -0
  257. data/rdoc/xorsin_log.html +22569 -0
  258. data/rubyneat.gemspec +347 -0
  259. data/rubyneat.gemspec.orig +375 -0
  260. data/spec/lib/rubyneat/rubyneat_spec.rb +132 -0
  261. metadata +555 -0
@@ -0,0 +1,227 @@
1
+ require 'rubyneat/rubyneat'
2
+
3
+ module NEAT
4
+ #= Population of NEAT Critters.
5
+ # The Population
6
+ # In ourselves we have the pool of neurons the critters all use.
7
+ # the pool of neurons are indirects, of course, as during phenotype
8
+ # expression, all the phenotypes shall be created individually.
9
+ #
10
+ class Population < NeatOb
11
+ # Ordered list or hash of input neuron classes
12
+ # (all critters generated here shall have this)
13
+ attr_accessor :input_neurons
14
+
15
+ # List of possible neuron classes for hidden neurons.
16
+ attr_accessor :hidden_neurons
17
+
18
+ # Ordered list or hash of output neuron classes
19
+ # (all critters generated here shall have this)
20
+ attr_accessor :output_neurons
21
+
22
+ attr_accessor :traits
23
+
24
+ # list of critter in this population
25
+ attr_accessor :critters
26
+
27
+ # Overall population fitness and novelty
28
+ attr_reader :fitness, :novelty
29
+
30
+ # Hash list of species lists
31
+ attr_reader :species
32
+
33
+ # in a deep dive, exclude the following from replication.
34
+ exclude :input_neurons, :output_neurons
35
+
36
+ # Create initial (ramdom) population of critters
37
+ def initialize(c, &block)
38
+ super
39
+ @input_neurons = c.neural_inputs.clone
40
+ @output_neurons = c.neural_outputs.clone
41
+ @hidden_neurons = unless c.neural_hidden.nil?
42
+ c.neural_hidden
43
+ else
44
+ c.neuron_catalog.keep_if {|n| not n.input?}
45
+ end
46
+ @critters = (0 ... c.parms.start_population_size || c.parms.population_size).map do
47
+ Critter.new(self)
48
+ end
49
+ block.(self) unless block.nil?
50
+ end
51
+
52
+ # Make sure all critters are reset and prepared for
53
+ # recurrent network evaluation.
54
+ def initialize_for_recurrence!
55
+ @critters.each {|crit| crit.initialize_neurons!}
56
+ end
57
+
58
+ # Mutate the genes and neurons.
59
+ def mutate!
60
+ @controller.evolver.mutate! self
61
+ end
62
+
63
+ # Express the entire population.
64
+ def express!
65
+ @critters.each { |critter| critter.express! }
66
+ end
67
+
68
+ # Called for each sequence.
69
+ def evaluate!
70
+ @critters.each { |critter| critter.evaluate! }
71
+ end
72
+
73
+ # Alalyze evaluation results.
74
+ def analyze!
75
+ @critters.each { |critter| @controller.evaluator.analyze_for_fitness! critter }
76
+ end
77
+
78
+ # Call this after evaluation.
79
+ # Returns a newly-evolved population.
80
+ def evolve
81
+ @controller.evolver.evolve self
82
+ end
83
+
84
+ # Group critters into species
85
+ # Note that the @species objects
86
+ # have useful singleton methods:
87
+ #* @species.member? -- checks all of the lists for membership, not just the hash
88
+ #* @species[crit].fitness -- fitness of the entire species
89
+ def speciate!
90
+ # We blow away existing species and create our own member? function
91
+ @species = {} # lists keyed by representative critter
92
+ def @species.member?(crit)
93
+ super.member?(crit) or self.map{|k, li| li.member? crit}.reduce{|t1, t2| t1 or t2 }
94
+ end
95
+
96
+ def @species.evaluate!
97
+ self.each do |k, sp|
98
+ sp.fitness = sp.map{|crit| crit.fitness}.reduce{|a,b| a+b} / sp.size
99
+ end
100
+ end
101
+
102
+ def @species.compactify!(parm)
103
+ mutt = self[:mutt] = self.map { |k, splist| [k, splist]}.reject {|k, splist|
104
+ splist.size >= parm.smallest_species
105
+ }.map { |k, splist|
106
+ self.delete k
107
+ splist
108
+ }.flatten
109
+
110
+ # FIXME this code is not dry!!!!
111
+ def mutt.fitness=(fit)
112
+ @fitness = fit
113
+ end
114
+
115
+ def mutt.fitness
116
+ @fitness
117
+ end
118
+
119
+ self.delete :mutt if self[:mutt].empty?
120
+ end
121
+
122
+ # Some convience parms
123
+ parm = @controller.parms
124
+
125
+ # And so now we iterate...
126
+ @critters.each do |crit|
127
+ wearein = false
128
+ @species.each do |ck, list|
129
+ delta = crit.compare(ck)
130
+ #log.debug { "delta for #{crit} and #{ck} is #{delta}" }
131
+ if delta < parm.compatibility_threshold
132
+ list << crit
133
+ wearein = true
134
+ break
135
+ end
136
+ end
137
+
138
+ # New species?
139
+ unless wearein
140
+ @species[crit] = species = [crit]
141
+ def species.fitness=(fit)
142
+ @fitness = fit
143
+ end
144
+ def species.fitness
145
+ @fitness
146
+ end
147
+ end
148
+ end
149
+
150
+ # Compactify the species if less than smallest_species
151
+ @species.compactify! parm
152
+
153
+ # And now we evaluate all species for fitness...
154
+ @species.evaluate!
155
+
156
+ # Dump for debugging reasons
157
+ @species.each do |k, sp|
158
+ log.debug ">> Species #{k} has #{sp.size} members with a #{sp.fitness} fitness"
159
+ end
160
+
161
+ end
162
+
163
+ #== Generate a report on the state of this population.
164
+ #
165
+ def report
166
+ {
167
+ fitness: report_fitness,
168
+ fitness_species: report_fitness_species,
169
+ best_critter: report_best_fit,
170
+ worst_critter: report_worst_fit,
171
+ }
172
+ end
173
+
174
+ # The "best critter" is the critter with the lowest (closet to zero)
175
+ # fitness rating.
176
+ def best_critter
177
+ unless @controller.compare_func.nil?
178
+ @critters.min {|a, b| @controller.compare_func.(a.fitness, b.fitness) }
179
+ else
180
+ @critters.min {|a, b| a.fitness <=> b.fitness}
181
+ end
182
+ end
183
+
184
+ # The "worst critter" is the critter with the highest (away from zero)
185
+ # fitness rating.
186
+ def worst_critter
187
+ unless @controller.compare_func.nil?
188
+ @critters.max {|a, b| @controller.compare_func.(a.fitness, b.fitness) }
189
+ else
190
+ @critters.max {|a, b| a.fitness <=> b.fitness}
191
+ end
192
+ end
193
+
194
+ def dump_s
195
+ to_s + "\npopulation:\n" + @critters.map{|crit| crit.dump_s }.join("\n")
196
+ end
197
+
198
+ protected
199
+ # report on many fitness metrics
200
+ def report_fitness
201
+ {
202
+ overall: @critters.map{|critter| critter.fitness}.reduce{|m, f| m + f} / @critters.size,
203
+ best: best_critter.fitness,
204
+ worst: worst_critter.fitness,
205
+ }
206
+ end
207
+
208
+ # report on the best and worst species
209
+ def report_fitness_species
210
+ {
211
+ best: nil,
212
+ worst: nil,
213
+ }
214
+ end
215
+
216
+ # Find the best fit critter
217
+ def report_best_fit
218
+ best_critter.phenotype.code
219
+ end
220
+
221
+ # Find the worst fit critter
222
+ def report_worst_fit
223
+ worst_critter.phenotype.code
224
+ end
225
+
226
+ end
227
+ end
@@ -0,0 +1,429 @@
1
+ require 'distribution'
2
+ require 'yaml'
3
+ require 'logger'
4
+ require 'awesome_print'
5
+ require 'deep_dive'
6
+
7
+ =begin rdoc
8
+ = RubyNEAT -- a Ruby Implementation of the NeuroEvolution by Augmented Topologies.
9
+
10
+ The RubyNEAT system incorporates the basis of the NEAT alorithm. Flexibility
11
+ is the key here, allowing RubyNEAT to be leverage in a varitety of applications.
12
+
13
+ === Requirements
14
+ We make no effort to support Ruby versions less than 1.9.2. I know this will
15
+ be a problem to some, but you are strongly urgerd to upgrade.
16
+
17
+ =end
18
+
19
+ $log = Logger.new(STDOUT)
20
+ $log.level = Logger::INFO
21
+ AwesomePrint.defaults = { plain: true }
22
+
23
+ =begin rdoc
24
+ = NEAT -- Module for RubyNEAT.
25
+
26
+ == Synopsis
27
+ We have a Population of Critters, and each Critter
28
+ represents a network of Neurons and a connection list specifying
29
+ how those Neurons are connected.
30
+
31
+ Each Neuron has an inplicit genotype and phenotype component. Neurons,
32
+ from the Ruby persoective, contain their own code to produce their own
33
+ phenotypes.
34
+
35
+ There are input Neurons and output Neurons. The input Neurons are special, as
36
+ they do not contain any input from other nodes, but serve as interfaces
37
+ from the "real world". Thier range of inputs are open, and it shall be up to
38
+ the input Neuron's phenotype generators to condition those inputs, if need be,
39
+ to someething more suiable for the neural network.
40
+
41
+ == Issues
42
+ === Multicore / Cloud Computing
43
+ Some thought needs to be given to how to make this anenable to multiple
44
+ processes so that we can leverage the power of multicore systems as well
45
+ as multiple computers in the Cloud, etc.
46
+
47
+ Our initial inclination is to put all of that functionality in the Conroller.
48
+ =end
49
+ module NEAT
50
+ @rng_count = 0
51
+ @rng_names = %w{aaa bee cex dee flo kis lee mor cie lou gir sex quo sam lac hin pee
52
+ cur set sew flat nac zac pae por lie lox pox nez fez wib poo sho
53
+ nuz tux que bsh shi her him can muk fuk kit kat uno dos ant mic
54
+ aa be nz oo py tt my of ze mu pi zz qu fl tr as sd fg gh hj bc
55
+ lion tame monk busy honk tape slap zonk funk tear flip shop soap
56
+ quay mony stir moot shoo slim fate trat beep kook love hate
57
+ mire hair lips funk open shut case lace joop lute doze fuzz
58
+ mean nice soil vote kick apes snak huge sine pine gray nook fool
59
+ woot hail smel tell jell suut gage phat pinoy spain rey bloke zit}
60
+ def self.random_name_generator
61
+ (1..3).map {
62
+ @rng_names[rand @rng_names.size]
63
+ }.push(@rng_count += 1).join('_').to_sym
64
+ end
65
+
66
+ # Name of the stimulus method in NEAT::Critter::Phenotype to use
67
+ # for the singleton method expression of the critter.
68
+ STIMULUS = :stimulate
69
+
70
+ # Mixin for new innovation numbers.
71
+ def self.new_innovation; @controller.new_innovation; end
72
+
73
+ # Mixin for the gaussian object.
74
+ def self.gaussian ; @controller.gaussian; end
75
+
76
+ # PrettyPrint to log.debug
77
+ def self.dpp ob
78
+ #$log.ap ob
79
+ end
80
+
81
+ # Basis of all NEAT objects
82
+ class NeatOb
83
+ include DeepDive
84
+ exclude :controller, :name
85
+
86
+ # Designation of this particular object instance
87
+ attr_reader :name
88
+
89
+ # Who's your daddy?
90
+ attr_reader :controller
91
+
92
+ def log ; $log ; end
93
+ def self.log ; $log; end
94
+
95
+ # Initializer for all NEAT objects. Requires that
96
+ # the controller object is specified for all classes
97
+ # with the exception of the Controller itself or the
98
+ # Controller's NeatSettings.
99
+ def initialize(controller = nil, name = nil)
100
+ @name = unless name.nil?
101
+ name.to_sym
102
+ else
103
+ NEAT::random_name_generator
104
+ end
105
+ unless controller.nil?
106
+ @controller = controller
107
+ else
108
+ raise NeatException.new "Controller Needed!" unless self.is_a?(Controller) or self.is_a?(Controller::NeatSettings)
109
+ @controller = self unless self.is_a? Controller::NeatSettings
110
+ end
111
+ end
112
+
113
+ def to_s
114
+ "%s<%s>" % [self.class, self.name]
115
+ end
116
+ end
117
+
118
+ class NeatException < Exception
119
+ end
120
+
121
+ #= Base class of operators in RubyNEAT,
122
+ # Such as Evolver, etc.
123
+ class Operator < NeatOb
124
+ end
125
+
126
+ #= Traits
127
+ # A Trait is a group of parameters that can be expressed
128
+ # as a group more than one time. Traits save a genetic
129
+ # algorithm from having to search vast parameter landscapes
130
+ # on every node. Instead, each node can simply point to a trait
131
+ # and those traits can evolve on their own. (Taken from the C version of NEAT)
132
+ #
133
+ # Since we wish to allow for different classes of Neurons, this trait idea is
134
+ # super, since all we need to do is have a different trait species for the
135
+ # different node types.
136
+ class Trait < NeatOb
137
+ end
138
+
139
+ require 'rubyneat/critter'
140
+ require 'rubyneat/neuron'
141
+ require 'rubyneat/population'
142
+ require 'rubyneat/evolver'
143
+ require 'rubyneat/expressor'
144
+ require 'rubyneat/evaluator'
145
+
146
+ #= Controller for all operations of RubyNEAT
147
+ # This object contains all the specifications and details for
148
+ # evolving and evaluation of the RubyNEAT system. It is
149
+ # a type of "World", if you will, for the entire enterprise.
150
+ #
151
+ # Your application shall only have one Controller.
152
+ class Controller < NeatOb
153
+ # global innovation number
154
+ attr_reader :glob_innov_num
155
+
156
+ # current sequence number being evaluated
157
+ attr_reader :seq_num
158
+
159
+ # Current generation count
160
+ attr_reader :generation_num
161
+
162
+ # catalog of neurons classes to use { weight => nclass, ... }
163
+ attr_accessor :neuron_catalog
164
+
165
+ # Class map of named input and output neurons (each critter will have
166
+ # instantiations of these) name: InputNeuralClass (usually InputNeuron)
167
+ attr_accessor :neural_inputs, :neural_outputs, :neural_hidden
168
+
169
+ # Parameters for evolution (NeatParameters)
170
+ attr_accessor :parms
171
+
172
+ # population object and class specification
173
+ attr_reader :population, :population_history, :population_class
174
+
175
+ attr_accessor :expressor, :expressor_class
176
+ attr_accessor :evaluator, :evaluator_class
177
+ attr_accessor :evolver, :evolver_class
178
+
179
+ # Global verbosity level:
180
+ ## 1 - normal (the default)
181
+ ## 2 - really verbose
182
+ ## 3 - maximally verbose
183
+ # Use in conjunction with log.debug
184
+ attr_accessor :verbosity
185
+
186
+ # Query function that Critters shall call.
187
+ attr_accessor :query_func
188
+
189
+ # Fitness function that Critters shall be rated on.
190
+ attr_accessor :fitness_func
191
+
192
+ # Recurrence function that Critters will yield to.
193
+ attr_accessor :recurrence_func
194
+
195
+ # Compare function for fitness
196
+ # Cost function for integrating in the cost to the fitness scalar.
197
+ attr_accessor :compare_func, :cost_func, :stop_on_fit_func
198
+
199
+ # End run function to call at the end of each generational run
200
+ # Also report_hook to dump reports for the user, etc.
201
+ attr_accessor :end_run_func, :report_hook
202
+
203
+ # Logger object for all of RubyNEAT
204
+ attr_reader :log
205
+
206
+ # Various parameters affecting evolution.
207
+ # Based somewhat on the C version of NEAT.
208
+ # TODO not all of these parameters are implemented yet!!!
209
+ class NeatSettings < NeatOb
210
+ ## RubyNEAT specific
211
+
212
+ # Set to true to returned named parameters as hashes to the fitness function
213
+ # (the default is to do ordered arrays)
214
+ attr_accessor :hash_on_fitness
215
+
216
+ ## based on the C version of NEAT
217
+ attr_accessor :age_significance
218
+ attr_accessor :babies_stolen
219
+
220
+ # Species compatability threshold
221
+ attr_accessor :compatibility_threshold
222
+
223
+ # Speciation coffficient
224
+ attr_accessor :disjoint_coefficient, :excess_coefficient, :weight_coefficient
225
+
226
+ # Max target number of species (will result in the compatability_coeifficient
227
+ # being adjusted automatically
228
+ attr_accessor :max_species
229
+
230
+ # Species Peality age for not making progress
231
+ attr_accessor :dropoff_age
232
+
233
+ # Species smallest population allowed (coalse smaller species into one)
234
+ attr_accessor :smallest_species
235
+
236
+ # Ratio of mating are actually interspecies
237
+ attr_accessor :interspecies_mate_rate
238
+
239
+ attr_accessor :linktrait_mutation_sig
240
+ attr_accessor :mate_multipoint_avg_prob
241
+ attr_accessor :mate_multipoint_prob
242
+ attr_accessor :mate_only_prob
243
+ attr_accessor :mate_singlepoint_prob
244
+
245
+ # Maximum number of generations to run, if given.
246
+ attr_accessor :max_generations
247
+
248
+ # Maximun number of populations to maintain in the history buffer.
249
+ attr_accessor :max_population_history
250
+
251
+ attr_accessor :mutate_add_gene_prob
252
+ attr_accessor :mutate_add_neuron_prob
253
+
254
+ attr_accessor :mutate_gene_disable_prob
255
+ attr_accessor :mutate_gene_reenable_prob
256
+
257
+ attr_accessor :mutate_gene_trait_prob
258
+
259
+ # For gene weights perturbations and changes (complete overwrites)
260
+ attr_accessor :mutate_perturb_gene_weights_prob,
261
+ :mutate_perturb_gene_weights_sd,
262
+ :mutate_change_gene_weights_prob,
263
+ :mutate_change_gene_weights_sd
264
+
265
+ attr_accessor :mutate_neuron_trait_prob
266
+ attr_accessor :mutate_only_prob
267
+ attr_accessor :mutate_random_trait_prob
268
+ attr_accessor :mutate_toggle_enable_prob
269
+ attr_accessor :mutdiff_coefficient
270
+ attr_accessor :newlink_tries
271
+ attr_accessor :neuron_trait_mut_sig
272
+
273
+ # fitness costs, if given, use in the computation of fitness
274
+ # AFTER the overall fitness for the applied stimuli have been
275
+ # caclulated.
276
+ attr_accessor :fitness_cost_per_neuron
277
+ attr_accessor :fitness_cost_per_gene
278
+
279
+ # If set, will start off at the specified size and
280
+ # grow to the bigger population size
281
+ attr_accessor :start_population_size, :population_size
282
+
283
+ attr_accessor :start_sequence_at, :end_sequence_at
284
+
285
+ attr_accessor :print_every
286
+ attr_accessor :recur_only_prob
287
+ attr_accessor :recur_prob
288
+
289
+ # factor (0 to 1) of the top percentage of the species that's
290
+ # allowed to mate.
291
+ attr_accessor :survival_threshold
292
+ attr_accessor :survival_mininum_per_species
293
+
294
+ attr_accessor :trait_mutation_power
295
+ attr_accessor :trait_param_mut_prob
296
+ attr_accessor :weigh_mut_power
297
+
298
+ # Enable FS-NEAT
299
+ attr_accessor :feature_selection_switch
300
+
301
+ # Enable HyperNEAT. This will result in the critters
302
+ # being interpreted as CPPNs for substrate weights. Additional
303
+ # setup will be necessary.
304
+ attr_accessor :hyper_switch
305
+
306
+ # Enable Evolved Substrate HyperNEAT. Meaningless unless
307
+ # hyper_switch is also enabled.
308
+ attr_accessor :evolved_substrate_switch
309
+
310
+ # Enable RT-NEAT, for gradual evolution suitable for
311
+ # games and other human-interactive systems.
312
+ attr_accessor :real_time_switch
313
+
314
+ # If true, allow for recurrent networks.
315
+ attr_accessor :recurrency_switch
316
+
317
+ # Set up defaults for mandatory entries.
318
+ def initialize
319
+ super
320
+ @start_sequence_at = 0
321
+ @end_sequence_at = 100
322
+ @max_generations = 1000
323
+
324
+ # Default operators
325
+ @evaluator = Evaluator.new self
326
+ @expressor = Expressor.new self
327
+ @evolver = Evolver.new self
328
+ end
329
+ end
330
+
331
+ #- neural_inputs -- array of input classes
332
+ #- neural_outputs -- array of output classes
333
+ #- parameters -- NeatParameters object, or a path to a YAML file to create this.
334
+ def initialize(neural_inputs: nil,
335
+ neural_outputs: nil,
336
+ neural_hidden: nil,
337
+ parameters: NeatSettings.new,
338
+ &block)
339
+ super(self)
340
+ @verbosity = 1
341
+ @glob_innov_num = 0
342
+ @gaussian = Distribution::Normal.rng
343
+ @population_history = []
344
+ @evolver = Evolver.new self
345
+ @expressor = Expressor.new self
346
+
347
+ @neuron_catalog = Neuron::neuron_types.clone
348
+ @neural_inputs = neural_inputs
349
+ @neural_outputs = neural_outputs
350
+ @neural_hidden = neural_hidden
351
+
352
+ # Default classes for population and operators, etc.
353
+ @population_class = NEAT::Population
354
+ @evaluator_class = NEAT::Evaluator
355
+ @expressor_class = NEAT::Expressor
356
+ @evolver_class = NEAT::Evolver
357
+
358
+ # Handle the parameters parameter. :-)
359
+ @parms = unless parameters.kind_of? String
360
+ parameters
361
+ else # load it from a file
362
+ open(parameters, 'r') { |fd| YAML::load fd.read }
363
+ end
364
+ block.(self) unless block.nil?
365
+ end
366
+
367
+ def new_innovation ; @glob_innov_num += 1; end
368
+ def gaussian ; @gaussian.() ; end
369
+
370
+ # Run this evolution.
371
+ def run
372
+ pre_run_initialize
373
+ (1..@parms.max_generations).each do |gen_number|
374
+ @generation_num = gen_number
375
+ @population_history << unless @population.nil?
376
+ @population
377
+ else
378
+ @population = @population_class.new(self)
379
+ end
380
+ @population_history.shift unless @population_history.size <= @parms.max_population_history
381
+ @population.mutate!
382
+ @population.express!
383
+
384
+ ## Evaluate population
385
+ @evaluator.ready_for_evaluation @population
386
+ (@parms.start_sequence_at .. @parms.end_sequence_at).each do |snum|
387
+ @seq_num = snum
388
+ @population.evaluate!
389
+ end
390
+
391
+ @population.analyze!
392
+ @population.speciate!
393
+
394
+ $log.debug @population.dump_s unless @verbosity < 3
395
+
396
+ new_pop = @population.evolve
397
+
398
+ ## Report hook for evaluation
399
+ @report_hook.(@population.report) unless @report_hook.nil?
400
+
401
+ ## Exit if fitness criteria is reached
402
+ #FIXME handle this exit condition better!!!!!
403
+ exit if @stop_on_fit_func.(@population.report[:fitness], self) unless @stop_on_fit_func.nil?
404
+
405
+ ## Evolve population
406
+ @population = new_pop
407
+
408
+ ## Finish up this run
409
+ @end_run_func.(self) unless @end_run_func.nil?
410
+ end
411
+ end
412
+
413
+ private
414
+ # We must set up the objects we need prior to the run, if not set.
415
+ def pre_run_initialize
416
+ @evaluator = @evaluator_class.new(self) if @evaluator.nil?
417
+ @evolver = @evolver_class.new(self) if @evolver.nil?
418
+ end
419
+ end
420
+
421
+ @controller = Controller.new
422
+ def self.controller ; @controller ; end
423
+ def self.controller=(controller) ; @controller = controller ; end
424
+ def self.create_controller(*parms); @controller = Controller.new(*parms); end
425
+ end
426
+
427
+ # We put all the internal requires at the end to avoid conflicts.
428
+ require 'rubyneat/neuron'
429
+ require 'rubyneat/population'
data/lib/rubyneat.rb ADDED
@@ -0,0 +1,8 @@
1
+ =begin rdoc
2
+ =RubyNEAT ()Neural Evolution via Augmented Topologies)
3
+ =end
4
+
5
+ require 'rubyneat/rubyneat'
6
+ require 'rubyneat/graph'
7
+ require 'rubyneat/dsl'
8
+ require 'set'