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.
- checksums.yaml +7 -0
- data/.directory +4 -0
- data/.gitignore.orig +20 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/dictionaries/trader.xml +3 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/rubyneat.iml +197 -0
- data/.idea/runConfigurations/invpend_neat.xml +26 -0
- data/.idea/runConfigurations/sigdebug_neat.xml +24 -0
- data/.idea/runConfigurations/xor_neat.xml +26 -0
- data/.idea/runConfigurations/xordebug_neat.xml +24 -0
- data/.idea/runConfigurations/xorsin_neat.xml +24 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +1124 -0
- data/.semver +5 -0
- data/.yardoc/checksums +11 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/Gemfile +32 -0
- data/Gemfile.lock +135 -0
- data/Gemfile.lock.orig +147 -0
- data/Guardfile +8 -0
- data/Rakefile +61 -0
- data/bin/neat +83 -0
- data/config/application.rb +5 -0
- data/doc/ControllerPoint.html +125 -0
- data/doc/CuteA.html +286 -0
- data/doc/CuteB.html +297 -0
- data/doc/DSL.html +883 -0
- data/doc/NEAT/BasicNeuronTypes/BiasNeuron.html +518 -0
- data/doc/NEAT/BasicNeuronTypes/CosineNeuron.html +274 -0
- data/doc/NEAT/BasicNeuronTypes/InputNeuron.html +366 -0
- data/doc/NEAT/BasicNeuronTypes/SigmoidNeuron.html +275 -0
- data/doc/NEAT/BasicNeuronTypes/SineNeuron.html +274 -0
- data/doc/NEAT/BasicNeuronTypes/TanhNeuron.html +274 -0
- data/doc/NEAT/BasicNeuronTypes.html +136 -0
- data/doc/NEAT/Controller/NeatSettings.html +3985 -0
- data/doc/NEAT/Controller.html +2490 -0
- data/doc/NEAT/Critter/Genotype/Gene.html +979 -0
- data/doc/NEAT/Critter/Genotype.html +1601 -0
- data/doc/NEAT/Critter/Phenotype.html +603 -0
- data/doc/NEAT/Critter.html +1037 -0
- data/doc/NEAT/DSL.html +1255 -0
- data/doc/NEAT/Evaluator.html +420 -0
- data/doc/NEAT/Evolver/CritterOp.html +551 -0
- data/doc/NEAT/Evolver.html +602 -0
- data/doc/NEAT/Expressor.html +327 -0
- data/doc/NEAT/Graph/DependencyResolver.html +478 -0
- data/doc/NEAT/Graph/GraphException.html +123 -0
- data/doc/NEAT/Graph.html +402 -0
- data/doc/NEAT/NeatException.html +123 -0
- data/doc/NEAT/NeatOb.html +567 -0
- data/doc/NEAT/Neuron.html +1067 -0
- data/doc/NEAT/Operator.html +162 -0
- data/doc/NEAT/Population.html +1961 -0
- data/doc/NEAT/Trait.html +169 -0
- data/doc/NEAT.html +588 -0
- data/doc/_index.html +373 -0
- data/doc/class_list.html +54 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +339 -0
- data/doc/file_list.html +53 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +373 -0
- data/doc/js/app.js +219 -0
- data/doc/js/full_list.js +178 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1415 -0
- data/doc/top-level-namespace.html +164 -0
- data/foo/foo_aquarium_example.rb +38 -0
- data/foo/foo_gosu.rb +99 -0
- data/foo/foo_rubygoo.rb +104 -0
- data/foo/foo_sdl.rb +34 -0
- data/foo/icon.png +0 -0
- data/lib/rubyneat/critter.rb +374 -0
- data/lib/rubyneat/default_neat.rb +10 -0
- data/lib/rubyneat/dsl.rb +130 -0
- data/lib/rubyneat/evaluator.rb +51 -0
- data/lib/rubyneat/evolver.rb +315 -0
- data/lib/rubyneat/expressor.rb +110 -0
- data/lib/rubyneat/graph.rb +95 -0
- data/lib/rubyneat/neuron.rb +152 -0
- data/lib/rubyneat/population.rb +227 -0
- data/lib/rubyneat/rubyneat.rb +429 -0
- data/lib/rubyneat.rb +8 -0
- data/neater/invpend_neat.rb +150 -0
- data/neater/rnlib/inverted_pendulum.rb +380 -0
- data/neater/rnlib/xor.rb +10 -0
- data/neater/sigdebug_neat.rb +136 -0
- data/neater/xor_neat.rb +137 -0
- data/neater/xoranalog_neat.rb +138 -0
- data/neater/xorsin_neat.rb +143 -0
- data/projectFilesBackup/.idea/rubyneat.iml +180 -0
- data/public/.directory +4 -0
- data/public/background.png +0 -0
- data/public/background.xcf +0 -0
- data/public/cart.png +0 -0
- data/public/cart.xcf +0 -0
- data/public/metalpoles_molton_ball_l.jpg +0 -0
- data/public/old_background.png +0 -0
- data/public/pointer.png +0 -0
- data/public/pointer.xcf +0 -0
- data/public/pole.kra +0 -0
- data/public/pole.png +0 -0
- data/public/pole.xcf +0 -0
- data/public/wheel-of-year-stone-DD-131-WOYS.jpg +0 -0
- data/public/wheel.png +0 -0
- data/public/wheel.xcf +0 -0
- data/public/wood-planks-texture.jpg +0 -0
- data/rdoc/ControllerPoint.html +116 -0
- data/rdoc/CuteA.html +177 -0
- data/rdoc/CuteB.html +178 -0
- data/rdoc/DSLSetup.html +177 -0
- data/rdoc/GameTestWindow.html +242 -0
- data/rdoc/GameWindow.html +292 -0
- data/rdoc/Gemfile.html +215 -0
- data/rdoc/Gemfile_lock.html +327 -0
- data/rdoc/GraphTest.html +210 -0
- data/rdoc/Guardfile.html +198 -0
- data/rdoc/InvertedPendulum/Cart.html +668 -0
- data/rdoc/InvertedPendulum/DSL.html +259 -0
- data/rdoc/InvertedPendulum/InvPendWindow.html +402 -0
- data/rdoc/InvertedPendulum.html +198 -0
- data/rdoc/Logger.html +98 -0
- data/rdoc/NEAT/BasicNeuronTypes/BiasNeuron.html +265 -0
- data/rdoc/NEAT/BasicNeuronTypes/CosineNeuron.html +162 -0
- data/rdoc/NEAT/BasicNeuronTypes/InputNeuron.html +206 -0
- data/rdoc/NEAT/BasicNeuronTypes/SigmoidNeuron.html +162 -0
- data/rdoc/NEAT/BasicNeuronTypes/SineNeuron.html +162 -0
- data/rdoc/NEAT/BasicNeuronTypes/TanhNeuron.html +161 -0
- data/rdoc/NEAT/BasicNeuronTypes.html +107 -0
- data/rdoc/NEAT/Controller/NeatSettings.html +880 -0
- data/rdoc/NEAT/Controller.html +729 -0
- data/rdoc/NEAT/Critter/Genotype/Gene.html +457 -0
- data/rdoc/NEAT/Critter/Genotype.html +735 -0
- data/rdoc/NEAT/Critter/Phenotype.html +330 -0
- data/rdoc/NEAT/Critter.html +489 -0
- data/rdoc/NEAT/DSL.html +729 -0
- data/rdoc/NEAT/Evaluator.html +256 -0
- data/rdoc/NEAT/Evolver/CritterOp.html +349 -0
- data/rdoc/NEAT/Evolver.html +891 -0
- data/rdoc/NEAT/Expressor.html +402 -0
- data/rdoc/NEAT/Graph/DependencyResolver.html +291 -0
- data/rdoc/NEAT/Graph/GraphException.html +105 -0
- data/rdoc/NEAT/Graph.html +263 -0
- data/rdoc/NEAT/NeatException.html +105 -0
- data/rdoc/NEAT/NeatOb.html +325 -0
- data/rdoc/NEAT/Neuron.html +481 -0
- data/rdoc/NEAT/Operator.html +109 -0
- data/rdoc/NEAT/Population.html +935 -0
- data/rdoc/NEAT/Trait.html +117 -0
- data/rdoc/NEAT.html +422 -0
- data/rdoc/Object.html +384 -0
- data/rdoc/Phi.html +98 -0
- data/rdoc/Player.html +383 -0
- data/rdoc/Rakefile.html +254 -0
- data/rdoc/RubyNEAT/Application.html +105 -0
- data/rdoc/RubyNEAT.html +98 -0
- data/rdoc/SDL/Event2.html +98 -0
- data/rdoc/SDL.html +98 -0
- data/rdoc/Vector.html +195 -0
- data/rdoc/created.rid +125 -0
- data/rdoc/doc/ControllerPoint_html.html +299 -0
- data/rdoc/doc/CuteA_html.html +438 -0
- data/rdoc/doc/CuteB_html.html +436 -0
- data/rdoc/doc/DSL_html.html +992 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes/BiasNeuron_html.html +617 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes/CosineNeuron_html.html +413 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes/InputNeuron_html.html +498 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes/SigmoidNeuron_html.html +413 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes/SineNeuron_html.html +413 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes/TanhNeuron_html.html +412 -0
- data/rdoc/doc/NEAT/BasicNeuronTypes_html.html +310 -0
- data/rdoc/doc/NEAT/Controller/NeatSettings_html.html +3324 -0
- data/rdoc/doc/NEAT/Controller_html.html +2212 -0
- data/rdoc/doc/NEAT/Critter/Genotype/Gene_html.html +997 -0
- data/rdoc/doc/NEAT/Critter/Genotype_html.html +1556 -0
- data/rdoc/doc/NEAT/Critter/Phenotype_html.html +687 -0
- data/rdoc/doc/NEAT/Critter_html.html +1037 -0
- data/rdoc/doc/NEAT/DSL_html.html +1349 -0
- data/rdoc/doc/NEAT/Evaluator_html.html +556 -0
- data/rdoc/doc/NEAT/Evolver/CritterOp_html.html +690 -0
- data/rdoc/doc/NEAT/Evolver_html.html +677 -0
- data/rdoc/doc/NEAT/Expressor_html.html +468 -0
- data/rdoc/doc/NEAT/Graph/DependencyResolver_html.html +598 -0
- data/rdoc/doc/NEAT/Graph/GraphException_html.html +299 -0
- data/rdoc/doc/NEAT/Graph_html.html +527 -0
- data/rdoc/doc/NEAT/NeatException_html.html +299 -0
- data/rdoc/doc/NEAT/NeatOb_html.html +671 -0
- data/rdoc/doc/NEAT/Neuron_html.html +1095 -0
- data/rdoc/doc/NEAT/Operator_html.html +337 -0
- data/rdoc/doc/NEAT/Population_html.html +1795 -0
- data/rdoc/doc/NEAT/Trait_html.html +344 -0
- data/rdoc/doc/NEAT_html.html +736 -0
- data/rdoc/doc/_index_html.html +559 -0
- data/rdoc/doc/class_list_html.html +369 -0
- data/rdoc/doc/css/common_css.html +188 -0
- data/rdoc/doc/css/full_list_css.html +243 -0
- data/rdoc/doc/css/style_css.html +530 -0
- data/rdoc/doc/file_list_html.html +240 -0
- data/rdoc/doc/frames_html.html +217 -0
- data/rdoc/doc/index_html.html +559 -0
- data/rdoc/doc/js/app_js.html +423 -0
- data/rdoc/doc/js/full_list_js.html +372 -0
- data/rdoc/doc/js/jquery_js.html +1536 -0
- data/rdoc/doc/method_list_html.html +1375 -0
- data/rdoc/doc/top-level-namespace_html.html +317 -0
- data/rdoc/fonts/Lato-Light.ttf +0 -0
- data/rdoc/fonts/Lato-LightItalic.ttf +0 -0
- data/rdoc/fonts/Lato-Regular.ttf +0 -0
- data/rdoc/fonts/Lato-RegularItalic.ttf +0 -0
- data/rdoc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/rdoc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/rdoc/fonts.css +167 -0
- data/rdoc/images/add.png +0 -0
- data/rdoc/images/arrow_up.png +0 -0
- data/rdoc/images/brick.png +0 -0
- data/rdoc/images/brick_link.png +0 -0
- data/rdoc/images/bug.png +0 -0
- data/rdoc/images/bullet_black.png +0 -0
- data/rdoc/images/bullet_toggle_minus.png +0 -0
- data/rdoc/images/bullet_toggle_plus.png +0 -0
- data/rdoc/images/date.png +0 -0
- data/rdoc/images/delete.png +0 -0
- data/rdoc/images/find.png +0 -0
- data/rdoc/images/loadingAnimation.gif +0 -0
- data/rdoc/images/macFFBgHack.png +0 -0
- data/rdoc/images/package.png +0 -0
- data/rdoc/images/page_green.png +0 -0
- data/rdoc/images/page_white_text.png +0 -0
- data/rdoc/images/page_white_width.png +0 -0
- data/rdoc/images/plugin.png +0 -0
- data/rdoc/images/ruby.png +0 -0
- data/rdoc/images/tag_blue.png +0 -0
- data/rdoc/images/tag_green.png +0 -0
- data/rdoc/images/transparent.png +0 -0
- data/rdoc/images/wrench.png +0 -0
- data/rdoc/images/wrench_orange.png +0 -0
- data/rdoc/images/zoom.png +0 -0
- data/rdoc/index.html +282 -0
- data/rdoc/js/darkfish.js +140 -0
- data/rdoc/js/jquery.js +18 -0
- data/rdoc/js/navigation.js +142 -0
- data/rdoc/js/search.js +109 -0
- data/rdoc/js/search_index.js +1 -0
- data/rdoc/js/searcher.js +228 -0
- data/rdoc/rdoc.css +580 -0
- data/rdoc/rubyneat_gemspec.html +387 -0
- data/rdoc/table_of_contents.html +2502 -0
- data/rdoc/xordebug_log.html +170598 -0
- data/rdoc/xorsin_log.html +22569 -0
- data/rubyneat.gemspec +347 -0
- data/rubyneat.gemspec.orig +375 -0
- data/spec/lib/rubyneat/rubyneat_spec.rb +132 -0
- 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
|