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,315 @@
1
+ require 'rubyneat'
2
+ require 'distribution'
3
+ module NEAT
4
+ #= Evolver -- Basis of all evolvers.
5
+ # All evolvers shall derive from this basic evolver (or this one can be
6
+ # used as is). Here, we'll have many different evolutionary operators
7
+ # that will perform operations on the various critters in the population.
8
+ #
9
+
10
+ class Evolver < Operator
11
+ attr_reader :npop
12
+
13
+ def initialize(c)
14
+ super
15
+ @critter_op = CritterOp.new self
16
+ end
17
+
18
+ # Generate the initial genes for a given genotype.
19
+ # We key genes off their innovation numbers.
20
+ def gen_initial_genes!(genotype)
21
+ genotype.genes = {}
22
+ genotype.neural_inputs.each do |s1, input|
23
+ genotype.neural_outputs.each do |s2, output|
24
+ g = Critter::Genotype::Gene[genotype, input, output, NEAT::controller.gaussian]
25
+ genotype.genes[g.innovation] = g
26
+ end
27
+ end
28
+ end
29
+
30
+ # Here we mutate the population.
31
+ def mutate!(population)
32
+ @npop = population
33
+
34
+ if @controller.parms.mate_only_prob.nil? or rand > @controller.parms.mate_only_prob
35
+ log.debug "[[[ Neuron and Gene Giggling!"
36
+ mutate_perturb_gene_weights!
37
+ mutate_change_gene_weights!
38
+ mutate_add_neurons!
39
+ mutate_change_neurons!
40
+ mutate_add_genes!
41
+ mutate_disable_genes!
42
+ mutate_reenable_genes!
43
+ log.debug "]]] End Neuron and Gene Giggling!\n"
44
+ else
45
+ log.debug "*** Mating only!"
46
+ end
47
+ end
48
+
49
+ # Here we clone the population and then evolve it
50
+ # on the basis of fitness and novelty, etc.
51
+ #
52
+ # Returns the newly-evolved population.
53
+ def evolve(population)
54
+ @npop = population.dclone
55
+
56
+ # Population sorting and evaluation for breeding, mutations, etc.
57
+ prepare_speciation!
58
+ prepare_fitness!
59
+ prepare_novelty!
60
+
61
+ mate!
62
+
63
+ return @npop
64
+ end
65
+
66
+ # Here we specify evolutionary operators.
67
+ protected
68
+
69
+ def prepare_speciation!
70
+ @npop.speciate!
71
+ log.debug "SPECIES:"
72
+ NEAT::dpp @npop.species
73
+ end
74
+
75
+ # Sort species within the basis of fitness.
76
+ # Think of the fitness as an error / cost function.
77
+ # The better fit, the closer to zero the fitness parameter will be.
78
+ #
79
+ # If a compare block is specified in the DSL, then that function is called
80
+ # with the *fitness values* from critters c1 and c2. The default valuation
81
+ # is c1.fitness <=> c2.fitness. You may elect to evaluate them differently.
82
+ def prepare_fitness!
83
+ @npop.species.each do |k, sp|
84
+ sp.sort!{|c1, c2|
85
+ unless @controller.compare_func.nil?
86
+ @controller.compare_func.(c1.fitness, c2.fitness)
87
+ else
88
+ c1.fitness <=> c2.fitness
89
+ end
90
+ }
91
+ end
92
+ end
93
+
94
+ #TODO: write novelty code
95
+ def prepare_novelty!
96
+ end
97
+
98
+ # Perturb existing gene weights by adding a guassian to them.
99
+ def mutate_perturb_gene_weights!
100
+ @gperturb = Distribution::Normal::rng(0, @controller.parms.mutate_perturb_gene_weights_sd) if @gperturb.nil?
101
+ @npop.critters.each do |critter|
102
+ critter.genotype.genes.each { |innov, gene|
103
+ if rand < @controller.parms.mutate_perturb_gene_weights_prob
104
+ gene.weight += per = @gperturb.()
105
+ log.debug { "Peturbed gene #{gene}.#{innov} by #{per}" }
106
+ end
107
+ }
108
+ end
109
+ end
110
+
111
+ # Totally change weights to something completely different
112
+ def mutate_change_gene_weights!
113
+ @gchange = Distribution::Normal::rng(0, @controller.parms.mutate_change_gene_weights_sd) if @gchange.nil?
114
+ @npop.critters.each do |critter|
115
+ critter.genotype.genes.each { |innov, gene|
116
+ if rand < @controller.parms.mutate_change_gene_weights_prob
117
+ gene.weight = chg = @gchange.()
118
+ log.debug { "Change gene #{gene}.#{innov} by #{chg}" }
119
+ end
120
+ }
121
+ end
122
+ end
123
+
124
+ def mutate_add_genes!
125
+ @npop.critters.each do |critter|
126
+ if rand < @controller.parms.mutate_add_gene_prob
127
+ log.debug "mutate_add_genes! for #{critter}"
128
+ @critter_op.add_gene! critter
129
+ end
130
+ end
131
+ end
132
+
133
+ def mutate_disable_genes!
134
+ @npop.critters.each do |critter|
135
+ if rand < @controller.parms.mutate_gene_disable_prob
136
+ log.debug "mutate_disable_genes! for #{critter}"
137
+ @critter_op.disable_gene! critter
138
+ end
139
+ end
140
+ end
141
+
142
+ def mutate_reenable_genes!
143
+ @npop.critters.each do |critter|
144
+ if rand < @controller.parms.mutate_gene_reenable_prob
145
+ log.debug "mutate_reenable_genes! for #{critter}"
146
+ @critter_op.reenable_gene! critter
147
+ end
148
+ end
149
+ end
150
+
151
+ def mutate_add_neurons!
152
+ @npop.critters.each do |critter|
153
+ if rand < @controller.parms.mutate_add_neuron_prob
154
+ log.debug "mutate_add_neurons! for #{critter}"
155
+ @critter_op.add_neuron! critter
156
+ end
157
+ end
158
+ end
159
+
160
+ # TODO Finish mutate_change_neurons!
161
+ def mutate_change_neurons!
162
+ log.error "mutate_change_neurons! NIY"
163
+ end
164
+
165
+ # Here we select candidates for mating. We must look at species and fitness
166
+ # to make the selection for mating.
167
+ def mate!
168
+ parm = @controller.parms
169
+ popsize = parm.population_size
170
+ surv = parm.survival_threshold
171
+ survmin = parm.survival_mininum_per_species
172
+ mlist = [] # list of chosen mating pairs of critters [crit1, crit2], or [:carryover, crit]
173
+
174
+ # species list already sorted in descending order of fitness.
175
+ # We will generate the approximate number of pairs that correspond
176
+ # to the survivial_threshold percentage of the population,
177
+ # then backfill with the most fit out of the top original population.
178
+ @npop.species.each do |k, sp|
179
+ crem = [(sp.size * surv).ceil, survmin].max
180
+ log.warn "Minumum per species hit -- #{survmin}" unless crem > survmin
181
+ spsel = sp[0, crem]
182
+ spsel = sp if spsel.empty?
183
+ crem.times do
184
+ mlist << [spsel[rand spsel.size], spsel[rand spsel.size]]
185
+ end
186
+ end
187
+
188
+ # And now for the backfilling
189
+ unless mlist.size >= @npop.critters.size
190
+ mlist += @npop.critters[0, @npop.critters.size - mlist.size].map{|crit| [:carryover, crit]}
191
+ end
192
+
193
+ @npop.critters = mlist.map do |crit1, crit2|
194
+ (crit1 == :carryover) ? crit2 : sex(crit1, crit2)
195
+ end
196
+ end
197
+
198
+ protected
199
+ # Mate the given critters and return a baby.
200
+ # This is rather involved, and relies heavily on the Innovation Numbers.
201
+ #
202
+ # Some definitions:
203
+ #
204
+ ## Matching Gene
205
+ ### 2 genes with matching innovation numbers.
206
+ #
207
+ ## Disjoint Gene
208
+ ### A gene in one has an innovation number in the range of innovation numbers
209
+ ### of the other.
210
+ #
211
+ ## Excess Gene
212
+ ### Gene in one critter that has an innovation number outside of the range
213
+ ### of innovation numbers of the other.
214
+ #
215
+ ## Neurons
216
+ ### Distinct Neurons from both crit1 and crit2 must be present in
217
+ ### the baby.
218
+ #
219
+ # Excess and Disjoint genes are always included from the more fit parent.
220
+ # Matching genes are randomly chosen. For now, we make it 50/50.
221
+ def sex(crit1, crit2)
222
+ Critter.new(@npop, true) do |baby|
223
+ fitcrit = if crit1.fitness > crit2.fitness
224
+ crit1
225
+ elsif crit2.fitness > crit1.fitness
226
+ crit2
227
+ else
228
+ (rand(2) == 1) ? crit1 : crit2
229
+ end
230
+ a = crit1.genotype.genes.keys.to_set
231
+ b = crit2.genotype.genes.keys.to_set
232
+ disjoint = (a - b) + (b - a)
233
+ joint = (a + b) - disjoint
234
+ baby.genotype.neucleate { |gtype|
235
+ joint.map { |innov|
236
+ g1 = crit1.genotype.genes[innov]
237
+ g2 = crit2.genotype.genes[innov]
238
+ Critter::Genotype::Gene[gtype,
239
+ g1.in_neuron, g1.out_neuron,
240
+ (rand(2) == 1) ? g1.weight : g2.weight,
241
+ innov]
242
+ } + disjoint.map { |innov|
243
+ fitcrit.genotype.genes[innov].clone unless fitcrit.genotype.genes[innov].nil?
244
+ }.reject{|i| i.nil? }
245
+ }
246
+ baby.genotype.innervate! crit1.genotype.neurons, crit2.genotype.neurons
247
+ baby.genotype.prune!
248
+ baby.genotype.wire!
249
+ end
250
+ end
251
+
252
+ # A set of Critter Genotype operators.
253
+ class CritterOp < NeatOb
254
+ def initialize(evol)
255
+ super evol.controller
256
+ @evolver = evol
257
+ @npop = evol.npop
258
+ end
259
+
260
+ #= Add a neuron to given critter
261
+ # Here, we add a neuron by randomly picking a
262
+ # gene, and split it into two genes with an intervening
263
+ # neuron. The old gene is not replaced, but disabled. 2 new genes are
264
+ # created along with the new neuron.
265
+ def add_neuron!(crit)
266
+ gene = crit.genotype.genes.values.sample
267
+ neu = controller.neural_hidden.values.sample.new(controller)
268
+ g1 = Critter::Genotype::Gene[crit.genotype, gene.in_neuron, neu.name, gene.weight]
269
+ g2 = Critter::Genotype::Gene[crit.genotype, neu.name, gene.out_neuron, gene.weight]
270
+ gene.enabled = false
271
+ crit.genotype.add_neurons neu
272
+ crit.genotype.add_genes g1, g2
273
+ log.debug "add_neuron!: neu #{neu}, g1 #{g1}, g2 #{g2}"
274
+ end
275
+
276
+ #= Add a gene to the genome
277
+ # Unlike adding a new neuron, adding a new gene
278
+ # could result in a circular dependency. If so,
279
+ # and if recurrency is switched off, we must detect
280
+ # this condition and switch off the offending neurons.
281
+ #
282
+ # Obviously, this might result in a loss of functionality, but
283
+ # oh well.
284
+ #
285
+ # An easy and obvious check is to make sure we don't
286
+ # accept any inputs from output neurons, and we don't
287
+ # do any outputs to input neurons.
288
+ #
289
+ # Constructs for handling recurrency are present in Expressor.
290
+ def add_gene!(crit)
291
+ n1 = crit.genotype.neurons.values.sample # input
292
+ n2 = crit.genotype.neurons.values.sample # output
293
+
294
+ # Sanity checks!
295
+ unless n1 == n2 or n1.output? or n2.input?
296
+ gene = Critter::Genotype::Gene[crit.genotype, n1.name, n2.name, NEAT::controller.gaussian]
297
+ crit.genotype.add_genes gene
298
+ log.debug "add_gene! Added gene #{gene}(#{n1.name} -> #{n2.name}) to #{crit}"
299
+ end
300
+ end
301
+
302
+ # Pick an enabled gene at random and disable it.
303
+ def disable_gene!(crit)
304
+ gene = crit.genotype.genes.values.reject{|gene| gene.disabled? }.sample
305
+ gene.enabled = false unless gene.nil?
306
+ end
307
+
308
+ # Pick a disabled gene at random and reenable it.
309
+ def reenable_gene!(crit)
310
+ gene = crit.genotype.genes.values.reject{|gene| gene.enabled? }.sample
311
+ gene.enabled = true unless gene.nil?
312
+ end
313
+ end
314
+ end
315
+ end
@@ -0,0 +1,110 @@
1
+ require 'rubyneat/rubyneat'
2
+ require 'pp'
3
+
4
+ module NEAT
5
+ #= Basis of all expressors.
6
+ # Expressor object turn genotypes into phenotypes.
7
+ class Expressor < Operator
8
+ def initialize(c)
9
+ super
10
+ end
11
+
12
+ # Take the genotype of the critter and
13
+ # create a phenotype from the genotype.
14
+ #
15
+ # In the phenotype, it creates a function called stimulate(),
16
+ # which is called with the input parameters and returns a response
17
+ # in the form of a response hash (which corresponds directly to the
18
+ # output neurons).
19
+ #
20
+ # This implementation assumes an acyclic graph (feed forward)
21
+ # and cannot handle cycles at all. Later we may fix this or create
22
+ # a type of Expressor that can.
23
+ def express!(critter)
24
+ critter.ready_for_expression!
25
+ express_neurons! critter
26
+ express_genes! critter
27
+ express_expression! critter
28
+ end
29
+
30
+ protected
31
+ # Express Neurons as methods
32
+ def express_neurons!(critter)
33
+ critter.genotype.neurons.each do |name, neuron|
34
+ neuron.express(critter.phenotype) unless neuron.input? and not neuron.bias?
35
+ end
36
+ end
37
+
38
+ #= Expression of the Genotype as a Phenotype.
39
+ # What this really does is create the function that calls
40
+ # all the functions.
41
+ #
42
+ # This makes use of the Graph plugin for Neurons.
43
+ #= Recurrency and Expression of Genes
44
+ # A simple approach has been taken here to allow for recurrency in
45
+ # our Critters. Basically, a looping construct has been put around the
46
+ # activation of the neurons so that recurrency can be done in 2 ways:
47
+ ## 1) Via yielding, thus treating the stimulus function as a enumerable.
48
+ ### In this approach, one would call the Critter's phenotype with a block of
49
+ ### code that would accept the output of the net. It would return 'true' to
50
+ ### continue the iteration, or 'false' to end the iteration.
51
+ ## 2) Via multiple calls to the Pheontype instance:
52
+ ### Since the value of the prior activation is preserved in the instance variables
53
+ ### of the phenotype, subsequent activations will iterate the network.
54
+ #== Cavets to recurrent activation
55
+ # For (2) above, the input neurons would be overwritten on each subsequent call.
56
+ # Since we do not allow recurrent connections to input neurons anyway, this should
57
+ # not be an issue, though we may allow for this at a future date.
58
+ def express_genes!(critter)
59
+ g = critter.genotype
60
+ p = critter.phenotype
61
+
62
+ init_code = "\n def initialize_neurons\n"
63
+
64
+ # 'stimulate' function call (really should be 'activate', but we'll reserve this for something else)
65
+ p.code += " def #{NEAT::STIMULUS}("
66
+ p.code += g.neural_inputs.reject{ |sym| g.neural_inputs[sym].bias? }.map{|sym, neu| sym}.join(", ")
67
+ p.code += ")\n"
68
+
69
+ # Assign all the parameters to instance variables.
70
+ p.code += g.neural_inputs.map{|sym, neu| " @#{sym} = #{sym}\n"}.join("")
71
+ p.code += " loop {\n"
72
+
73
+ # Resolve the order in which we shall call the neurons
74
+ # TODO handle the dependency list if it comes back!
75
+ @resolved, @dependencies = NEAT::Graph::DependencyResolver[g.neural_outputs.map{|s, neu| neu}].resolve
76
+
77
+ # And now call them in that order!
78
+ @resolved.each do |neu|
79
+ unless neu.input?
80
+ init_code += " @#{neu.name} = 0\n"
81
+ if g.neural_gene_map.member? neu.name
82
+ p.code += " @#{neu.name} = #{neu.name}("
83
+ p.code += g.neural_gene_map[neu.name].map{ |gene|
84
+ "%s * @%s" % [gene.weight, gene.in_neuron]
85
+ }.join(", ") + ")\n"
86
+ else
87
+ g.dangling_neurons = true
88
+ log.debug "Dangling neuron in critter #{critter} -- #{neu}"
89
+ end
90
+ end
91
+ end
92
+ init_code += " end\n"
93
+
94
+ # And now return the result as a vector of outputs.
95
+ p.code += " @_outvec = [" + g.neural_outputs.map{|sym, neu| "@#{sym}"}.join(',') + "]\n"
96
+ p.code += " break unless block_given?\n"
97
+ p.code += " break unless yield @_outvec\n"
98
+ p.code += " }\n"
99
+ p.code += " @_outvec\n"
100
+ p.code += " end\n"
101
+ p.code += init_code
102
+ log.debug p.code
103
+ p.express!
104
+ end
105
+
106
+ def express_expression!(critter)
107
+ critter.phenotype.express!
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,95 @@
1
+ require 'rubyneat'
2
+
3
+ module NEAT
4
+ # General graph representation
5
+ # (mainly used for Neurons, but could be used
6
+ # for other structures.)
7
+ #
8
+ # This is a mixin for Neuron and whatever else you'd like.
9
+ # the contained class is for evaluation, and may be instantiated separately.
10
+ module Graph
11
+ class GraphException < Exception
12
+ end
13
+
14
+ # clear and initialize the graph.
15
+ def clear_graph
16
+ @g_inputs = []
17
+ end
18
+
19
+ def << (input)
20
+ @g_inputs << input
21
+ self
22
+ end
23
+
24
+ # Add a single input
25
+ def add (input)
26
+ @g_inputs << input
27
+ end
28
+
29
+ # Get list of inputs
30
+ def inputs
31
+ raise GraphException.new "Graph Failure -- input is nil" if @g_inputs.nil?
32
+ @g_inputs
33
+ end
34
+
35
+ # Create an instantiation of this and pass it a list of nodes to resolve.
36
+ class DependencyResolver < NeatOb
37
+
38
+ # Given a list of output nodes, we shall work backwards
39
+ # from them to resolve their dependencies.
40
+ def initialize(outputs, &block)
41
+ @outputs = outputs
42
+ super
43
+ block.(self) unless block.nil?
44
+ end
45
+
46
+ # Create a DependencyResolver from either
47
+ # an array of outputs or a parameter list of outputs.
48
+ def self.[](*outs)
49
+ outs = outs.first if outs.first.kind_of? Array
50
+ DependencyResolver.new outs
51
+ end
52
+
53
+
54
+ # Resolve dependencies, and return [dependency_list, circular_ref_node_list]
55
+ # Note that circular_ref_node_list shall be nil if there are no dependencies!
56
+ def resolve
57
+ @resolved = []
58
+ @unresolved = []
59
+ @circular = []
60
+ @outputs.each do |onode|
61
+ rdep onode
62
+ end
63
+ [@resolved, @circular.empty? ? nil : @circular]
64
+ end
65
+
66
+ # Throw an exception if dependencies are found.
67
+ # We only return the dependency list since we throw an exception on circular
68
+ # dependencies.
69
+ def resolve!
70
+ dl, cl = resolve
71
+ raise GraphException("Circular Dependency Detected: %s" % cl) unless cl.nil?
72
+ dl
73
+ end
74
+
75
+ private
76
+ # recursive resolution of nodes
77
+ def rdep(node)
78
+ @unresolved << node
79
+ node.inputs.each { |inode|
80
+ if not @resolved.member? inode
81
+ unless @unresolved.member? inode
82
+ rdep inode
83
+ else
84
+ # we found a circular reference.
85
+ @circular << inode
86
+ #log.warn "Dependency found: %s" % inode
87
+ end
88
+ end
89
+ }
90
+ @resolved << node
91
+ @unresolved.delete node
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,152 @@
1
+ require 'rubyneat'
2
+ require 'rubyneat/graph'
3
+
4
+ =begin rdoc
5
+ = Neuron Types
6
+
7
+ We create all the neuron types for this system here.
8
+
9
+ =end
10
+ module NEAT
11
+ #= Neuron -- Basis of all Neat Neuron types.
12
+ # Normally contains primatives which aids in its
13
+ # own expression, but the details of this remains to be worked out.
14
+ class Neuron < NeatOb
15
+ include Math
16
+ include Graph
17
+
18
+ # Genotype to which we belong
19
+ attr_reader :genotype
20
+ attr_accessor :trait
21
+
22
+ # (assigned by wire!) Heirarchy number in the Genome / Critter
23
+ # We need this to assure we add genes in the proper order.
24
+ # This will be recalculated every time a new neuron is added.
25
+ attr_accessor :heirarchy_number
26
+
27
+ # This is true if this is an output neuron.
28
+ attr_accessor :output
29
+
30
+ # List of neuron types defined.
31
+ @@neuron_types = []
32
+
33
+ # Class is is of Input type?
34
+ def self.input? ; false ; end
35
+ def input? ; self.class.input? ; end
36
+
37
+ def self.bias? ; false ; end
38
+ def bias? ; self.class.bias? ; end
39
+
40
+ # Instantiation is of outout type?
41
+ def output? ; !!@output ; end
42
+
43
+ def self.inherited(clazz)
44
+ @@neuron_types << clazz
45
+ end
46
+
47
+ # List of distinct neuron types (classes)
48
+ def self.neuron_types; @@neuron_types ; end
49
+
50
+ # Function must be implemented by subclasses for phenotype
51
+ # generation. Basically, an instance is passed to this function
52
+ # and it will add a function to sum all inputs
53
+ # and a apply an operator to the sum.
54
+ def express(instance)
55
+ raise NeatException.new "express() must be implemented by subclass."
56
+ end
57
+ end
58
+
59
+
60
+
61
+ =begin rdoc
62
+ = Basic Neuron Types
63
+
64
+ Basically, the neurons (nodes) will have an instantiation to represent their places in the
65
+ neural net, and way to spin up the phenotypic representation.
66
+
67
+ The basic types to RubyNEAT are represented here.
68
+ =end
69
+ module BasicNeuronTypes
70
+ #= Special class of Neuron that takes input from the "real world"
71
+ # Name of this neuron equates to the parameter name of the input.
72
+ #
73
+ # All inputs are handled with this neuron. This type of
74
+ # neuron only has one input -- from the outside world.
75
+ class InputNeuron < NEAT::Neuron
76
+ def self.input? ; true ; end
77
+
78
+ # Takes a single input and passes it as is.
79
+ def express(instance)
80
+ instance.define_singleton_method(@name) {|input|
81
+ input
82
+ }
83
+ end
84
+ end
85
+
86
+ #= Special class of neuron that provides a bias signal.
87
+ # FIXME: The bias value is not behaving as expected because
88
+ # FIXME: the instance is not the neuron, but the phenotype.
89
+ class BiasNeuron < InputNeuron
90
+ def self.bias? ; true ; end
91
+ attr_accessor :neu_bias
92
+
93
+ def initialize(c=nil, n=nil)
94
+ super
95
+ @neu_bias = 1.00
96
+ end
97
+
98
+ # Just provides a bias signal
99
+ # FIXME: we had to hard-code the value here for now. Not a biggie,
100
+ # FIXME: but really should be @neu_bias
101
+ def express(instance)
102
+ instance.define_singleton_method(@name) { 1.00 }
103
+ end
104
+ end
105
+
106
+ # The most commonly-used neuron for the hidden and output layers.
107
+ # We use the Logistic Function for the Sigmoid.
108
+ class SigmoidNeuron < Neuron
109
+ # create a function on the instance with our name
110
+ # that sums all inputs and produce a sigmoid output (using tanh)
111
+ def express(instance)
112
+ instance.define_singleton_method(@name) {|*inputs|
113
+ 1.0 / (1.0 + exp(-4.9 * inputs.reduce {|p, q| p + q}))
114
+ }
115
+ end
116
+ end
117
+
118
+ # An alternative Sigmoid Function, but ranges -1 to +1
119
+ class TanhNeuron < Neuron
120
+ # create a function on the instance with our name
121
+ # that sums all inputs and produce a sigmoid output (using tanh)
122
+ def express(instance)
123
+ instance.define_singleton_method(@name) {|*inputs|
124
+ tanh(2.4 * inputs.reduce {|p, q| p + q})
125
+ }
126
+ end
127
+ end
128
+
129
+ # Sin function (CPPN) -- adjusted to have its +1 and -1 near TanhNeuron
130
+ class SineNeuron < Neuron
131
+ # create a function on the instance with our name
132
+ # that sums all inputs and produce a sigmoid output (using tanh)
133
+ def express(instance)
134
+ instance.define_singleton_method(@name) {|*inputs|
135
+ sin(1.6 * inputs.reduce {|p, q| p + q})
136
+ }
137
+ end
138
+ end
139
+
140
+ # Cosine function (CPPN) -- adjusted to have its +1 and -1 near TanhNeuron
141
+ class CosineNeuron < Neuron
142
+ # create a function on the instance with our name
143
+ # that sums all inputs and produce a sigmoid output (using tanh)
144
+ def express(instance)
145
+ instance.define_singleton_method(@name) {|*inputs|
146
+ cos(1.6 * inputs.reduce {|p, q| p + q})
147
+ }
148
+ end
149
+ end
150
+
151
+ end
152
+ end