rubyneat 0.3.5.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
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