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,374 @@
1
+ require 'rubyneat'
2
+
3
+ =begin rdoc
4
+ = Critter
5
+ =end
6
+ module NEAT
7
+
8
+ #= Critters for NEAT
9
+ # The Critter class comprises a Genotype and a Phenotype.
10
+ # The Genotype comprises Genes and Neurons.
11
+ class Critter < NeatOb
12
+ attr_reader :population
13
+ attr_accessor :genotype, :phenotype
14
+
15
+ # Ratings assigned by Evaluator
16
+ attr_accessor :fitness, :novelty
17
+
18
+ # Critter construction. We construct the genotype.
19
+ # The phenotype will be constructed by the Expressor operator.
20
+ def initialize(pop, mating = false, &block)
21
+ super pop.controller
22
+ @population = pop
23
+ @genotype = Genotype.new(self, mating)
24
+ block.(self) unless block.nil?
25
+ end
26
+
27
+ # Get the Critter ready for the Expressor to
28
+ # express the geneotype.
29
+ def ready_for_expression!
30
+ @genotype.wire!
31
+ @phenotype = NEAT::Critter::Phenotype[self]
32
+ @phenotype
33
+ end
34
+
35
+ # Exoress this critter using the Expressor plugin.
36
+ def express!
37
+ @controller.expressor.express! self
38
+ end
39
+
40
+ # This initializes neurons in preparation for recurrence.
41
+ # Note that the Critter should already have expressed its
42
+ # genotype before this is called.
43
+ def initialize_neurons!
44
+ @phenotype.initialize_neurons
45
+ end
46
+
47
+ # A single evaluation step. Evaluate and
48
+ # generate fitness, novelty, etc.
49
+ # Returns the result.
50
+ def evaluate!
51
+ @controller.evaluator.evaluate! self
52
+ end
53
+
54
+ #= Genotype part of the Critter
55
+ # List of connections, basically.
56
+ #
57
+ # Also, basic phentypic expression (which may be overriden by
58
+ # the expressor)
59
+ #
60
+ #= Notes
61
+ # Currently, all lists of neurons and genes are Hashes. The
62
+ # neurons are indexed by their own names, and the genes
63
+ # are indexed by their innovation numbers.
64
+ #
65
+ class Genotype < NeatOb
66
+ # Critter to which we belong
67
+ attr_accessor :critter
68
+
69
+ # Genes keyed by innovation numbers
70
+ attr_accessor :genes
71
+
72
+ # List of neurons hashed by name
73
+ attr_accessor :neurons
74
+
75
+ # Instantiations of neural inputs and outputs
76
+ attr_reader :neural_inputs, :neural_outputs
77
+
78
+ # This will be set to true if there are dangling neurons.
79
+ attr_accessor :dangling_neurons
80
+ alias :dangling_neurons? :dangling_neurons
81
+
82
+ # Map neurons to the genes that marks them as output
83
+ # { oneu_name => [ gene_1, gene_2,... gene_n], ...}
84
+ # Just take the in_neuron name and the weight to do
85
+ # the call to that neuron function with the appropriate weights
86
+ attr_reader :neural_gene_map
87
+
88
+ def initialize(critter, mating = false, &block)
89
+ super critter.controller
90
+ @critter = critter
91
+
92
+ # Initialize basic structures
93
+ @genes = nil
94
+ @neural_inputs = Hash[@critter.population.input_neurons.map { |sym, ineu|
95
+ [sym, ineu.new(@controller, sym)]
96
+ }]
97
+
98
+ @neural_outputs = Hash[@critter.population.output_neurons.map { |sym, ineu|
99
+ [sym, ineu.new(@controller, sym)]
100
+ }]
101
+ @neurons = @neural_inputs.clone # this must be a shallow clone!
102
+ @neurons.merge! @neural_outputs
103
+
104
+ @controller.evolver.gen_initial_genes!(self) unless mating
105
+ block.(self) unless block.nil?
106
+ end
107
+
108
+ # We add genes given here to the genome.
109
+ # An array of genes is returned from the block
110
+ # and we simply add them in.
111
+ # @param [boolean] clean
112
+ # @param [Proc] block
113
+ def neucleate(clean: true, &block)
114
+ genes = Hash[block.(self).map { |g|
115
+ g.genotype = self
116
+ [g.innovation, g] }]
117
+ if clean
118
+ @genes = genes
119
+ else
120
+ @genes.merge! genes
121
+ end
122
+ nuke_redundancies!
123
+ end
124
+
125
+ # Remove any redundancies in the genome,
126
+ # any genes refering to the same two neurons.
127
+ # Simply choose one and delete the rest.
128
+ # TODO: implement nuke_redundancies!
129
+ def nuke_redundancies!
130
+ log.warn 'nuke_redundancies! NIY'
131
+ end
132
+
133
+ # Make the neurons forget their wiring.
134
+ def forget!
135
+ @neurons.each { |name, neu| neu.clear_graph }
136
+ @neural_gene_map = Hash.new {|h, k| h[k] = [] }
137
+ end
138
+
139
+ # Wire up the neurons based on the genes.
140
+ def wire!
141
+ forget!
142
+ @genes.each do |innov, gene|
143
+ if gene.enabled?
144
+ raise NeatException.new "Can't find #{gene.out_neuron}" if @neurons[gene.out_neuron].nil?
145
+ @neurons[gene.out_neuron] << @neurons[gene.in_neuron]
146
+ @neural_gene_map[gene.out_neuron] << gene unless gene.in_neuron.nil?
147
+ end
148
+ end unless @genes.nil?
149
+ if @genes.nil?
150
+ $log.error 'Genes Not Present'
151
+ end
152
+ end
153
+
154
+ # Add new neurons to the fold
155
+ def add_neurons(*neus)
156
+ neus.each do |neu|
157
+ @neurons[neu.name] = neu
158
+ end
159
+ end
160
+
161
+ # Genes added here MUST correspond to pre-existing neurons.
162
+ # Be sure to do add_neurons first!!!!
163
+ def add_genes(*genes)
164
+ genes.each do |gene|
165
+ raise NeatException.new "Neuron #{gene.in_neuron} missing" unless @neurons.member? gene.in_neuron
166
+ raise NeatException.new "Neuron #{gene.out_neuron} missing" unless @neurons.member? gene.out_neuron
167
+ @genes[gene.innovation] = gene
168
+ end
169
+ end
170
+
171
+ # We take the neural hashes (presumably from other neurons), and innervate them.
172
+ # We do this in distinctions based on the neuron's names.
173
+ # FIXME We need to randomly select a neuron in the case of clashes.
174
+ # @param [Hash] hneus -- hashes of neurons to innervate
175
+ def innervate!(*hneus)
176
+ hneus.each do |neus|
177
+ @neurons.merge! neus.dclone
178
+ end
179
+ end
180
+
181
+ # Go through the list of neurons and drop
182
+ # any neurons not referenced by the genes.
183
+ #
184
+ # Then go through the genes and drop any that
185
+ # are dangling (i.e. no matching neurons)
186
+ #
187
+ # Then make sure that @neural_inputs and @neural_outputs reference the actual
188
+ # instance neurons in @neurons
189
+ #
190
+ # TODO add this circularity check to prune!
191
+ def prune!
192
+ # Take care of dangling neurons
193
+ neunames = @genes.values.map{|g| [g.in_neuron, g.out_neuron]}.flatten.to_set
194
+ @neurons = Hash[@neurons.values.reject do |n|
195
+ not neunames.member? n.name
196
+ end.map do |n|
197
+ [n.name, n]
198
+ end]
199
+
200
+ # Take care of dangling genes
201
+ @genes = Hash[@genes.values.reject do |gene|
202
+ not (@neurons.member?(gene.in_neuron) and @neurons.member?(gene.out_neuron))
203
+ end.map do |gene|
204
+ [gene.name, gene]
205
+ end]
206
+
207
+ # Make sure @neural_inputs and @neural_outputs are consistent
208
+ @neural_inputs = Hash[@neural_inputs.values.map{|n| [n.name, @neurons[n.name]]}]
209
+ @neural_outputs = Hash[@neural_outputs.values.map{|n| [n.name, @neurons[n.name]]}]
210
+ end
211
+
212
+ # Calculate the cost of this genotype.
213
+ def fitness_cost
214
+ p = @controller.parms
215
+ p.fitness_cost_per_neuron * @neurons.size + p.fitness_cost_per_gene * @genes.size
216
+ end
217
+
218
+ def dump_s
219
+ to_s + "\ngenes:\n" + @genes.map{|k, gene|
220
+ gene.to_s}.join("\n") + "\nneurons:\n" + @neurons.map{|k, neu|
221
+ neu.to_s}.join("\n")
222
+ end
223
+
224
+ #= Gene Specification
225
+ # The Gene specifices a singlular input and
226
+ # output neuron, which represents a connection
227
+ # between them, along with the weight of that
228
+ # connection, which may be positive, negative, or zero.
229
+ #
230
+ # There is also the enabled flag
231
+ class Gene < NeatOb
232
+ # parent genotype
233
+ attr_accessor :genotype
234
+
235
+ # innovation number
236
+ attr_accessor :innovation
237
+
238
+ # input neuron's name (where our output goes)
239
+ # ouptut neuron's name (neuron to be queried)
240
+ attr_accessor :in_neuron, :out_neuron
241
+
242
+ # weight of the connection
243
+ attr_accessor :weight
244
+ # Is this gene enabled?
245
+ attr_accessor :enabled
246
+
247
+ def initialize(genotype, &block)
248
+ super genotype.controller
249
+ @genotype = genotype
250
+ @enabled = true
251
+ @innovation = NEAT::new_innovation
252
+ @in_neuron = @out_neuron = nil
253
+ block.(self) unless block.nil?
254
+ end
255
+
256
+ def enabled? ; @enabled ; end
257
+ def disabled? ; not enabled? ; end
258
+
259
+ # Create a new Gene and set it up fully.
260
+ ## genotype -- genotype
261
+ ## input -- name of input neuron connection
262
+ ## output -- name of output neuron connection
263
+ ## weight -- weight to give neuron (optional)
264
+ ## innov -- innovation number of gene (optional)
265
+ def self.[](genotype, input, output, weight = 0.0, innov = nil)
266
+ g = Gene.new genotype
267
+ g.in_neuron = (input.kind_of? Symbol) ? input : input.name
268
+ g.out_neuron = (output.kind_of? Symbol) ? output : output.name
269
+ g.weight = weight
270
+ g.innovation = innov unless innov.nil?
271
+ return g
272
+ end
273
+
274
+ def to_s
275
+ super + "[i%s,w%s,%s]" % [@innovation, @weight, self.enabled?]
276
+ end
277
+ alias_method :dump_s, :to_s
278
+
279
+ end
280
+
281
+ end
282
+
283
+ #= Phenotype part of the Critter
284
+ # This is created by Evolver.
285
+ class Phenotype < NeatOb
286
+ include Math
287
+
288
+ # Critter to which we belong
289
+ attr_accessor :critter
290
+
291
+ # Expressed code as a string (that was instance_eval()ed)
292
+ attr_accessor :code
293
+
294
+ def self.[](critter)
295
+ ph = Phenotype.new critter.controller
296
+ ph.critter = critter
297
+ ph.code = "## Phenotype Code %s for critter %s\n" % [ph.name, critter.name]
298
+ return ph
299
+ end
300
+
301
+ # Take what is in code and express that!
302
+ def express!
303
+ instance_eval @code
304
+ self
305
+ end
306
+
307
+ # This function is re-written by Expressor -- with parameters and all.
308
+ # It returns a "response" in the form of a response hash.
309
+ # TODO This *is* network activation, so we should rename this at a later date...
310
+ def stimulate
311
+ nil
312
+ end
313
+
314
+ # This gives us a complete
315
+ def to_s
316
+ "## %s\n%s" % [super, @code]
317
+ end
318
+ end
319
+
320
+ # Compare ourselves against another critter for
321
+ # compability.
322
+ #
323
+ # The function to be used here is:
324
+ ## distance = c1*E + c2*D + c3*W
325
+ #
326
+ # Where:
327
+ ## E, D - The number of excess and disjoint genes repesctively.
328
+ ## N - The number of genes in the largest genome.
329
+ ## W - The sum of absolute weight differences.
330
+ #
331
+ # This is a variation of the formulation suggested by the Stanley
332
+ # paper, which normalizes the E and D terms by N.
333
+ def compare(oc)
334
+ c1 = @controller.parms.excess_coefficient
335
+ c2 = @controller.parms.disjoint_coefficient
336
+ c3 = @controller.parms.weight_coefficient
337
+ e = excess(oc)
338
+ d = disjoint(oc)
339
+ w = weight_diff(oc)
340
+ return c1 * e + c2 * d + c3 * w
341
+ end
342
+
343
+ # Critter print
344
+ def dump_s
345
+ to_s + @genotype.dump_s + "\n" + @phenotype.to_s + "\n"
346
+ end
347
+
348
+ private
349
+ # Return a count of excesses.
350
+ def excess(oc)
351
+ (@genotype.genes.size - oc.genotype.genes.size).abs
352
+ end
353
+
354
+ # Return the count of disjoint genes
355
+ def disjoint(oc)
356
+ a = @genotype.genes.keys
357
+ b = oc.genotype.genes.keys
358
+ (a - b).size + (b - a).size - excess(oc)
359
+ end
360
+
361
+ #
362
+ def weight_diff(oc)
363
+ ag = @genotype.genes
364
+ bg = oc.genotype.genes
365
+ matches = ag.keys & bg.keys
366
+ unless matches.empty?
367
+ matches.map{|i| (ag[i].weight - bg[i].weight).abs}.reduce{|w, ws| w + ws} / matches.size
368
+ else
369
+ 0
370
+ end
371
+ end
372
+
373
+ end
374
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubyneat/dsl'
2
+ =begin rdoc
3
+ = Default Parameters for RubyNEAT
4
+ Here all default parameters are defined.
5
+ =end
6
+
7
+ include NEAT::DSL
8
+
9
+ define "Default Parameters" do
10
+ end
@@ -0,0 +1,130 @@
1
+ require 'rubyneat/rubyneat'
2
+
3
+ =begin rdoc
4
+ = RubyNEAT DSL
5
+ DSL is a domain-specific language for RubyNEAT to allow you to configure the NEAT engine
6
+ for various evolutionary projects.
7
+ =end
8
+ module NEAT
9
+ module DSL
10
+ include NEAT
11
+ include NEAT::BasicNeuronTypes
12
+ include Math
13
+
14
+ # DSL -- Define defines the parameters to the controller.
15
+ def define(name = NEAT.random_name_generator, &block)
16
+ [
17
+ :inputs,
18
+ :outputs,
19
+ :hidden # we really don't care about mapping hidden neurons, but we'll ignore them later.
20
+ ].each do |iometh|
21
+ instance_eval %Q[
22
+ def #{iometh}(nodes = nil, &block)
23
+ neui = unless nodes.nil?
24
+ nodes
25
+ else
26
+ block.()
27
+ end
28
+ NEAT::controller.neural_#{iometh} = if neui.kind_of? Hash
29
+ neui
30
+ else
31
+ Hash[neui.map{|n| [NEAT::random_name_generator, n]}]
32
+ end
33
+ end]
34
+ end
35
+ block.(NEAT::controller)
36
+ end
37
+
38
+ # DSL -- Run evolution
39
+ def evolve(&block)
40
+ # Query function is called with the sequence (time evolution) number,
41
+ # and returns an array or hash of parameters that will be given
42
+ # to the input nodes. In the case of hash, the keys in the hash
43
+ # shall correspond to the names given to the input neurons.
44
+ def query(&block)
45
+ NEAT::controller.query_func = block
46
+ end
47
+
48
+ def recurrence(&block)
49
+ NEAT::controller.recurrence_func = block
50
+ end
51
+
52
+ # fitness function calls the block with 2 vectors or two hashes, input and output
53
+ # vectors of the critter being evaluated for fitness, as well as a sequence
54
+ # number that can be used to index what the actual output should be.
55
+ # |vin, vout, seq|
56
+ def fitness(&block)
57
+ NEAT::controller.fitness_func = block
58
+ end
59
+
60
+ # Fitness ordering -- given 2 fitness numbers,
61
+ # use the <=> to compare them (or the equivalent, following
62
+ # the +1, 0, -1 that is in the sense of <=>)
63
+ def compare(&block)
64
+ NEAT::controller.compare_func = block
65
+ end
66
+
67
+ # Calculation to add the cost to the fitness, resulting in a fitness
68
+ # that incorporates the cost for sorting purposes.
69
+ def cost(&block)
70
+ NEAT::controller.cost_func = block
71
+ end
72
+
73
+ # Stop the progression once the fitness criteria is reached
74
+ # for the most fit critter
75
+ def stop_on_fitness(&block)
76
+ NEAT::controller.stop_on_fit_func = block
77
+ end
78
+
79
+ # Helper function to
80
+ # Condition boolean vectors to be +1 if true, -1 if false (0 if sigmoid)
81
+ def condition_boolean_vector(vec, sig = :tanh)
82
+ vec.map{|b| b ? 1 : ((sig == :sigmoid) ? 0 : -1)}
83
+ end
84
+
85
+ # Helper function to
86
+ # Uncondition boolean vectors to be +1 if true, -1 if false
87
+ # FIXME we need a better discrimination function
88
+ def uncondition_boolean_vector(vec, sig = :tanh)
89
+ vec.map{|o| o > ((sig == :sigmoid) ? 0.5 : 0) ? true : false}
90
+ end
91
+
92
+ # Helper function to do a simple fitness calculation
93
+ # on the basis of the sum of the square of the diffences
94
+ # of the element in the two vectors.
95
+ def simple_fitness_error(v1, v2)
96
+ sqrt v1.zip(v2).map{|a, b| (a - b) ** 2.0}.reduce{|m, c| m + c}
97
+ end
98
+
99
+ block.(NEAT::controller)
100
+ end
101
+
102
+ # Report on evaluations
103
+ def report(&block)
104
+ NEAT::controller.report_hook = block
105
+ end
106
+
107
+ # Run the engine. The block is called on each generation.
108
+ def run_engine(&block)
109
+ NEAT::controller.end_run_func = block
110
+ NEAT::controller.run
111
+ end
112
+
113
+ # This is used to handle the details of our DSL.
114
+ def method_missing(m, *args, &block)
115
+ # we want to catch parameters settings here.
116
+ if NEAT::controller.parms.respond_to? (assignment = (m.to_s + '=').to_sym)
117
+ raise NeatException.new("Missing value(s) to %s" % m) if args.empty?
118
+ val = (args.size == 1) ? args[0] : args
119
+ $log.debug { "Caught method %s with parameter of %s" % [assignment, val] }
120
+ NEAT::controller.parms.send(assignment, val)
121
+ else
122
+ super
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ # FIXME: This needs to better specified for cases in which there may be multiple
129
+ # Controllers.
130
+ require 'rubyneat/default_neat'
@@ -0,0 +1,51 @@
1
+ require 'rubyneat/rubyneat'
2
+
3
+ module NEAT
4
+ #= Evaluator evaluates phenotype of critter for fitness, novelty, etc.
5
+ # We can have a chain of these evaluators whose outputs are summed, etc.
6
+ class Evaluator < Operator
7
+
8
+ # This is call prior to any sequence evaluation. Here,
9
+ # we clean up persistent tracking information, etc.
10
+ def ready_for_evaluation(pop)
11
+ @crit_hist = {}
12
+ pop.initialize_for_recurrence!
13
+ end
14
+
15
+ # Evaluate one step of a sequence of evaluations.
16
+ # For time series and realtime ongoing evaluations,
17
+ # @controller.seq_num governs where in the sequence
18
+ # everything is.
19
+ #
20
+ # Returns [vin, vout], where vin is the input vector,
21
+ # and vout in the output vector from the critter.
22
+ # FIXME: this should not really have to deal with an error.
23
+ # FIXME: the error should be handled upstream from here.
24
+ def evaluate!(critter)
25
+ vin = @controller.query_func.(@controller.seq_num)
26
+ @crit_hist[critter] = {} unless @crit_hist.member? critter
27
+ begin
28
+ vout = critter.phenotype.stimulate *vin, &@controller.recurrence_func
29
+ log.debug "Critter #{critter.name}: vin=#{vin}. vout=#{vout}"
30
+ @crit_hist[critter][@controller.seq_num] = [vin, vout]
31
+ rescue Exception => e
32
+ log.error "Exception #{e} on code:\n#{critter.phenotype.code}"
33
+ @crit_hist[critter][@controller.seq_num] = [vin, :error]
34
+ end
35
+ end
36
+
37
+ # Analyze the evaluation and compute a fitness for the given critter.
38
+ # Note that if cost_func is set, we call that to integrate the cost to
39
+ # the fitness average fitness calculated for the fitness vector.
40
+ def analyze_for_fitness!(critter)
41
+ fitvec = @crit_hist[critter].map{|seq, vio| @controller.fitness_func.(vio[0], vio[1], seq) }
42
+ # Average the fitness vector to get a scalar fitness.
43
+ critter.fitness = unless @controller.cost_func.nil?
44
+ @controller.cost_func.(fitvec, critter.genotype.fitness_cost)
45
+ else
46
+ fitvec.reduce {|a,r| a+r} / fitvec.size.to_f + critter.genotype.fitness_cost
47
+ end
48
+ log.debug "Fitness Vector: #{fitvec}, fitness of #{critter.fitness} assigned to #{critter}"
49
+ end
50
+ end
51
+ end