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,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