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,150 @@
|
|
|
1
|
+
#!/usr/bin/env neat
|
|
2
|
+
require 'rubyneat/dsl'
|
|
3
|
+
require 'inverted_pendulum'
|
|
4
|
+
|
|
5
|
+
include NEAT::DSL
|
|
6
|
+
include InvertedPendulum::DSL
|
|
7
|
+
|
|
8
|
+
=begin rdoc
|
|
9
|
+
=Inverted Pendulum
|
|
10
|
+
=end
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
invpend do |ipwin|
|
|
14
|
+
puts "Inverted Pendulum -- use the mouse wheel to bang the cart yourself."
|
|
15
|
+
|
|
16
|
+
c = cart do
|
|
17
|
+
{
|
|
18
|
+
scale: 0.20,
|
|
19
|
+
ang: 80,
|
|
20
|
+
xpos: 600.0,
|
|
21
|
+
cartmass: 200.0, #kg
|
|
22
|
+
polemass: 100.10, #kg, knobby end only
|
|
23
|
+
bang: 10.0, # acceleration on a bang event
|
|
24
|
+
thrust_decay: 2.0, # thrust decay percentage per second
|
|
25
|
+
window_pix_width: 1280,
|
|
26
|
+
naked: true # Naked cart, not attached to a window.
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
show cart: c
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
define "InvPend System" do
|
|
34
|
+
#-----------------------------------------------------
|
|
35
|
+
#= Neuron Specifications
|
|
36
|
+
inputs(
|
|
37
|
+
in_cart_velocity: InputNeuron,
|
|
38
|
+
in_cart_position: InputNeuron,
|
|
39
|
+
in_pole_velocity: InputNeuron,
|
|
40
|
+
in_pole_angle: InputNeuron,
|
|
41
|
+
bias: BiasNeuron
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
outputs out_bang_left: TanhNeuron, out_bang_right: TanhNeuron
|
|
45
|
+
|
|
46
|
+
hidden tan: TanhNeuron
|
|
47
|
+
|
|
48
|
+
#-----------------------------------------------------
|
|
49
|
+
#= Settings
|
|
50
|
+
# General
|
|
51
|
+
hash_on_fitness false
|
|
52
|
+
start_population_size 30
|
|
53
|
+
population_size 30
|
|
54
|
+
max_generations 10000
|
|
55
|
+
max_population_history 10
|
|
56
|
+
|
|
57
|
+
#-----------------------------------------------------
|
|
58
|
+
#= Evolver probabilities and SDs
|
|
59
|
+
# Perturbations
|
|
60
|
+
mutate_perturb_gene_weights_prob 0.10
|
|
61
|
+
mutate_perturb_gene_weights_sd 0.25
|
|
62
|
+
|
|
63
|
+
# Complete Change of weight
|
|
64
|
+
mutate_change_gene_weights_prob 0.10
|
|
65
|
+
mutate_change_gene_weights_sd 1.00
|
|
66
|
+
|
|
67
|
+
# Adding new neurons and genes
|
|
68
|
+
mutate_add_neuron_prob 0.05
|
|
69
|
+
mutate_add_gene_prob 0.20
|
|
70
|
+
|
|
71
|
+
# Switching genes on and off
|
|
72
|
+
mutate_gene_disable_prob 0.01
|
|
73
|
+
mutate_gene_reenable_prob 0.01
|
|
74
|
+
|
|
75
|
+
interspecies_mate_rate 0.03
|
|
76
|
+
mate_only_prob 0.10 #0.7
|
|
77
|
+
|
|
78
|
+
# Mating
|
|
79
|
+
survival_threshold 0.20 # top % allowed to mate in a species.
|
|
80
|
+
survival_mininum_per_species 4 # for small populations, we need SOMETHING to go on.
|
|
81
|
+
|
|
82
|
+
# Fitness costs
|
|
83
|
+
fitness_cost_per_neuron 0#.00001
|
|
84
|
+
fitness_cost_per_gene 0#.00001
|
|
85
|
+
|
|
86
|
+
# Speciation
|
|
87
|
+
compatibility_threshold 2.5
|
|
88
|
+
disjoint_coefficient 0.6
|
|
89
|
+
excess_coefficient 0.6
|
|
90
|
+
weight_coefficient 0.2
|
|
91
|
+
max_species 20
|
|
92
|
+
dropoff_age 15
|
|
93
|
+
smallest_species 5
|
|
94
|
+
|
|
95
|
+
# Sequencing
|
|
96
|
+
start_sequence_at 0
|
|
97
|
+
end_sequence_at 200
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
evolve do
|
|
101
|
+
# Each sequence query represents a time instant
|
|
102
|
+
# for evaluating the inverse pendulum.
|
|
103
|
+
#
|
|
104
|
+
# For this, we use a named vector (just a Hash, really),
|
|
105
|
+
# so we can ensure that the input parameters are lined up with
|
|
106
|
+
# the appropriate input neurons. When using named vectors,
|
|
107
|
+
# any non-matches are ignored, allowing you to play around
|
|
108
|
+
# with changes in input neurons with ease.
|
|
109
|
+
query { |seq|
|
|
110
|
+
# TODO: do an interation with the cart and return results.
|
|
111
|
+
# FIXME: how do we know this is a new sequence? I suppose we can
|
|
112
|
+
# FIXME: tell that the start number has been hit again.
|
|
113
|
+
{
|
|
114
|
+
in_cart_velocity: 0,
|
|
115
|
+
in_cart_position: 0,
|
|
116
|
+
in_pole_velocity: 0,
|
|
117
|
+
in_pole_angle: 0
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Compare the fitness of two critters.
|
|
122
|
+
# We may choose a different ordering here.
|
|
123
|
+
compare {|f1, f2| f2 <=> f1 }
|
|
124
|
+
|
|
125
|
+
# Here we integrate the cost with the fitness.
|
|
126
|
+
cost { |fitvec, cost|
|
|
127
|
+
#fit = XOR_STATES - fitvec.reduce {|a,r| a+r} - cost
|
|
128
|
+
#$log.debug ">>>>>>> fitvec #{fitvec} => #{fit}, cost #{cost}"
|
|
129
|
+
#fit
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fitness { |vin, vout, seq|
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
stop_on_fitness {|fitness, c|
|
|
136
|
+
puts "*** Generation Run #{c.generation_num}, best is #{fitness[:best]} ***\n\n"
|
|
137
|
+
fitness[:best] >= ALMOST_FIT
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
report do |rept|
|
|
142
|
+
$log.info "REPORT #{rept.to_yaml}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# The block here is called upon the completion of each generation
|
|
146
|
+
run_engine do |c|
|
|
147
|
+
$log.info "******** Run of generation %s completed, history count %d ********" %
|
|
148
|
+
[c.generation_num, c.population_history.size]
|
|
149
|
+
end
|
|
150
|
+
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
=begin rdoc
|
|
2
|
+
=Inverted Pendulum Experiment
|
|
3
|
+
|
|
4
|
+
Here we provide a graphic visualization of the inverted pendulum
|
|
5
|
+
problem, so you can actually SEE the problem being solved by
|
|
6
|
+
RubyNEAT.
|
|
7
|
+
|
|
8
|
+
==Notes
|
|
9
|
+
===Physical Quantities
|
|
10
|
+
All physical quantities are in SI units.
|
|
11
|
+
|
|
12
|
+
===Vectors
|
|
13
|
+
* We use 3 dimensional vectors here, even though it's a 2D simulation, for the
|
|
14
|
+
simple reason that cross products require at least 3 components to a vector.
|
|
15
|
+
* x and z are taken to be on the horizontal plane, and y is taken to be the vertical.
|
|
16
|
+
* The sign of the *graphical* y will be reversed of the physical y.
|
|
17
|
+
=end
|
|
18
|
+
|
|
19
|
+
require 'gosu'
|
|
20
|
+
require 'matrix'
|
|
21
|
+
|
|
22
|
+
module InvertedPendulum
|
|
23
|
+
include Math
|
|
24
|
+
GC = 6.67384e-11 # m3 kg-1 s-2
|
|
25
|
+
ADTG = -9.81 # m/s**2, acceleration due to gravity on earth
|
|
26
|
+
TORAD = PI / 180.0 # converts degrees to radians, deg * TORAD
|
|
27
|
+
PI2 = 2.0 * PI
|
|
28
|
+
|
|
29
|
+
# The following are array indicies of the vector.
|
|
30
|
+
X = 0 # Horizontal, cart travels in this coordinate.
|
|
31
|
+
Y = 1 # Vertical, gravitation acts in this coordinate
|
|
32
|
+
Z = 2 # Horizontal, purely there so the cross products work
|
|
33
|
+
|
|
34
|
+
GV = Vector[0, ADTG, 0]
|
|
35
|
+
ZERO_VECTOR = Vector[0,0,0]
|
|
36
|
+
|
|
37
|
+
# ID INPUTS
|
|
38
|
+
MOUSE_LB = 256
|
|
39
|
+
MOUSE_RB = 257
|
|
40
|
+
MOUSE_MB = 258
|
|
41
|
+
MOUSE_ROLL_BACK = 260
|
|
42
|
+
MOUSE_ROLL_FOREWARD = 259
|
|
43
|
+
MOUSE_SIDE_BACK = 268
|
|
44
|
+
MOUSE_SIDE_FOREWARD = 264
|
|
45
|
+
|
|
46
|
+
# We do this for speedier simulations, otherwise Vector is immutable.
|
|
47
|
+
class ::Vector
|
|
48
|
+
def []=(i, v)
|
|
49
|
+
@elements[i] = v
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Given that self vector is a basis vector,
|
|
53
|
+
# compute the component vector for v.
|
|
54
|
+
def basis(v)
|
|
55
|
+
self * self.inner_product(v)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class InvPendWindow < Gosu::Window
|
|
60
|
+
attr_accessor :cart
|
|
61
|
+
attr_reader :pix_width, :pix_height
|
|
62
|
+
|
|
63
|
+
def initialize(width: 1280, height: 1024)
|
|
64
|
+
super(@pix_width = width, @pix_height = height, false)
|
|
65
|
+
self.caption = "RubyNEAT Inverted Pendulum Simulation -- use mouse wheel to bang the cart."
|
|
66
|
+
|
|
67
|
+
@background = {image: Gosu::Image.new(self, 'public/background.png', true),
|
|
68
|
+
x: 0,
|
|
69
|
+
y: 0,
|
|
70
|
+
scale: 1.0
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def update
|
|
75
|
+
@cart.update unless @cart.nil?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def draw
|
|
79
|
+
@background[:image].draw(@background[:x],
|
|
80
|
+
@background[:y],
|
|
81
|
+
0,
|
|
82
|
+
@background[:scale],
|
|
83
|
+
@background[:scale])
|
|
84
|
+
|
|
85
|
+
@cart.draw unless cart.nil?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def needs_cursor?; true; end
|
|
89
|
+
|
|
90
|
+
def button_down(id)
|
|
91
|
+
@cart.button_down(id) unless @cart.nil?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def button_up(id)
|
|
95
|
+
@cart.button_up(id) unless @cart.nil?
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class Cart
|
|
100
|
+
attr_accessor :pix_meters # pixels per meter
|
|
101
|
+
attr_accessor :ipwin
|
|
102
|
+
|
|
103
|
+
#@param ipwin -- the windowed canvalss this will be shown.
|
|
104
|
+
#@param scale -- visual scale on the canvas.
|
|
105
|
+
#@param ang -- initial angle in degrees, 0 being the
|
|
106
|
+
# positive side of the x axis.
|
|
107
|
+
#@param xpos -- initial x position of the center of cart, in pixels.
|
|
108
|
+
#@param cartmass -- in kg. included are the mass of the wheels.
|
|
109
|
+
# We will not deal with the angular momentum
|
|
110
|
+
# of the wheels, because that's beyond the scope
|
|
111
|
+
# of what this is supposed to accomplish.
|
|
112
|
+
#@param polemass -- in kg. The mass of the pole is assumed to all
|
|
113
|
+
# reside at a point at
|
|
114
|
+
# the knobby end.
|
|
115
|
+
#@param bang -- per mouse event, how much bang (acceleration in m/s) to
|
|
116
|
+
# deliver to the cart
|
|
117
|
+
def initialize(ipwin: nil,
|
|
118
|
+
scale: 0.50,
|
|
119
|
+
ang: 90.1,
|
|
120
|
+
xpos: 500.0,
|
|
121
|
+
ypos: 845.0,
|
|
122
|
+
cartmass: 200.0,
|
|
123
|
+
polemass: 100.10,
|
|
124
|
+
bang: 10.0, # acceleration on a bang event
|
|
125
|
+
thrust_decay: 2.0, # thrust decay percentage per second
|
|
126
|
+
window_pix_width: 1280,
|
|
127
|
+
update_interval: 16.666666,
|
|
128
|
+
naked: false)
|
|
129
|
+
@t = 0
|
|
130
|
+
@bang = bang
|
|
131
|
+
@thrust = 0 # accumulated bang
|
|
132
|
+
@thrust_decay = thrust_decay
|
|
133
|
+
@scale = scale
|
|
134
|
+
@cart_length = 5.0 # meters
|
|
135
|
+
@pix_meters = 640.0 * scale / @cart_length
|
|
136
|
+
@ipwin = ipwin
|
|
137
|
+
@pix_width = @ipwin.nil? ? window_pix_width : @ipwin.pix_width
|
|
138
|
+
@update_interval = ipwin.nil? ? update_interval : @ipwin.update_interval
|
|
139
|
+
@cart = {
|
|
140
|
+
pos: Vector[xpos / @pix_meters, ypos / @pix_meters, 0],
|
|
141
|
+
vel: Vector[0.0, 0, 0], #speed in meters per second
|
|
142
|
+
acc: Vector[0.0, 0, 0], #acceleration in meters per second squared
|
|
143
|
+
scale: 0.2 * scale,
|
|
144
|
+
length: nil, # in meters, calculated from the scaled pixel length.
|
|
145
|
+
height: nil, # in meters, calculated from the scaled pixel height
|
|
146
|
+
basis: {
|
|
147
|
+
horiz: Vector[1.0, 0.0, 0.0], # The cart is resticted to movement on the x axis
|
|
148
|
+
vert: Vector[0.0, 1.0, 0.0]}, # so these basis vectors will never change.
|
|
149
|
+
force: {},
|
|
150
|
+
mass: cartmass
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Pole is relative to cart, and in the image is laying horizontal.
|
|
154
|
+
@pole = {
|
|
155
|
+
z: 0,
|
|
156
|
+
xoff: 0.0,
|
|
157
|
+
yoff: 0.5,
|
|
158
|
+
ang: ang, # angle is in degrees
|
|
159
|
+
dang: 0.0, # degrees per second
|
|
160
|
+
ddang: nil, # angular acceleration, degree / second ** 2
|
|
161
|
+
cdang: 0.0, # degrees per second, contribution from cart
|
|
162
|
+
cddang: nil, # angular acceleration, degree / second ** 2, contribution from cart
|
|
163
|
+
scale: 0.2 * scale,
|
|
164
|
+
force: {}, # shall hold the 2 force vectors :shaft and :radial
|
|
165
|
+
basis: {}, # basis (unit) vectors
|
|
166
|
+
cacc: Vector[0,0,0], # acceleration from cart
|
|
167
|
+
length: nil, # in meters, calculated from the scaled pixel length.
|
|
168
|
+
mass: polemass
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# Wheels is relative to cart
|
|
172
|
+
@wheels = [
|
|
173
|
+
{
|
|
174
|
+
ang: 0,
|
|
175
|
+
dang: 100, #FIXME: delete this for this will be overwritten anyway
|
|
176
|
+
xoff: -0.7, # percentage from center
|
|
177
|
+
yoff: 0.4, # percentage from center
|
|
178
|
+
scale: 0.2 * scale
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
ang: 0,
|
|
182
|
+
dang: 12.33, #FIXME: delete this for this will be overwritten anyway
|
|
183
|
+
xoff: 0.7,
|
|
184
|
+
yoff: 0.4,
|
|
185
|
+
scale: 0.2 * scale
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def ipwin=(ipwin)
|
|
191
|
+
@ipwin = ipwin
|
|
192
|
+
@cart[:image] = Gosu::Image.new(ipwin, 'public/cart.png', true)
|
|
193
|
+
@pole[:image] = Gosu::Image.new(ipwin, 'public/pole.png', true)
|
|
194
|
+
@wheels.each {|w|
|
|
195
|
+
w[:image] = Gosu::Image.new(ipwin, 'public/wheel.png', true)
|
|
196
|
+
# radius of wheel in meters, need this for rotational velocity calculation
|
|
197
|
+
w[:radius] = w[:image].width * w[:scale] / @pix_meters / 2.0
|
|
198
|
+
w[:circumference] = w[:radius] * 2.0 * PI
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@cart[:length] = @cart[:image].width * @cart[:scale] / @pix_meters
|
|
202
|
+
@cart[:height] = @cart[:image].height * @cart[:scale] / @pix_meters
|
|
203
|
+
@pole[:length] = @pole[:image].width * @pole[:scale] / @pix_meters
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Provide a bang for the cart.
|
|
207
|
+
# Return a thrust (acc) vector (really just x)
|
|
208
|
+
# based on thrust
|
|
209
|
+
#@param bb -- bang factor, normally -1, 0, or 1, but could be
|
|
210
|
+
# other values based on being a multiplier of the actual bang to be
|
|
211
|
+
# applied.
|
|
212
|
+
def big_bang(bb = 0)
|
|
213
|
+
# FIXME: this is temporary. Eventually this will call a callback in the Neater script.
|
|
214
|
+
v = Vector[@thrust, 0, 0]
|
|
215
|
+
@thrust += @bang * bb
|
|
216
|
+
@thrust -= @thrust * @thrust_decay * @dt
|
|
217
|
+
v
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def button_down(id)
|
|
221
|
+
big_bang case id
|
|
222
|
+
when MOUSE_ROLL_FOREWARD
|
|
223
|
+
1.0
|
|
224
|
+
when MOUSE_ROLL_BACK
|
|
225
|
+
-1.0
|
|
226
|
+
else
|
|
227
|
+
0
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def button_up(id)
|
|
232
|
+
# no op for now.
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def update
|
|
236
|
+
## Physics updates
|
|
237
|
+
@dt = @update_interval / 1000.0
|
|
238
|
+
@t += @dt
|
|
239
|
+
|
|
240
|
+
## Pole (Pendulum) forces, accelerations, etc.
|
|
241
|
+
# basis vectors
|
|
242
|
+
ang = @pole[:ang] * TORAD
|
|
243
|
+
@pole[:time] = @t
|
|
244
|
+
@pole[:basis][:shaft] = iShaft = Vector[cos(ang), sin(ang), 0]
|
|
245
|
+
@pole[:basis][:radial] = iRadial = Vector[sin(ang), -cos(ang), 0]
|
|
246
|
+
@pole[:r] = r = iShaft * @pole[:length]
|
|
247
|
+
@pole[:force][:shaft] = iShaft.basis(GV * @pole[:mass])
|
|
248
|
+
@pole[:force][:radial] = radial = iRadial.basis(GV * @pole[:mass])
|
|
249
|
+
# the magnitude of the radial vector goes to the torque on
|
|
250
|
+
@pole[:force][:torque] = torque = r.cross_product(radial)
|
|
251
|
+
@pole[:alpha] = alpha = torque / (@pole[:mass] * (@pole[:length] ** 2.0))
|
|
252
|
+
@pole[:ddang] = -alpha[Z] / TORAD # the pseudo vector component Z is the signed magnitude
|
|
253
|
+
@pole[:dang] += @pole[:ddang] * @dt # angular velocity
|
|
254
|
+
@pole[:vel] = @pole[:basis][:radial] * (@pole[:dang] * TORAD * PI2 * @pole[:length]) #linear velocity at the pole mass
|
|
255
|
+
@pole[:ang] += @pole[:dang] * @dt
|
|
256
|
+
|
|
257
|
+
## Cart forces from pole [:force][:shaft] and centifugal
|
|
258
|
+
@cart[:time] = @t
|
|
259
|
+
|
|
260
|
+
@pole[:force][:centrifugal] = centrifugal = (@pole[:basis][:shaft] * @pole[:vel].magnitude ** 2) * @pole[:mass]
|
|
261
|
+
@cart[:force][:shaft] = shaft = @pole[:force][:shaft] # + centrifugal #FIXME cemtrifugal calculations wonky!
|
|
262
|
+
@cart[:force][:horiz] = horiz = @cart[:basis][:horiz].basis shaft
|
|
263
|
+
@cart[:force][:vert] = @cart[:basis][:vert].basis shaft # not that we use the vert
|
|
264
|
+
|
|
265
|
+
# Now the horz force induces an acceleration on the cart.
|
|
266
|
+
# Any additions to the acceleration vector must be done after
|
|
267
|
+
# this point.
|
|
268
|
+
@cart[:acc] = horiz / (@cart[:mass] + @pole[:mass] * cos(ang).abs)
|
|
269
|
+
|
|
270
|
+
@cart[:acc] += big_bang
|
|
271
|
+
|
|
272
|
+
## Cart acceleration also affects angular torque
|
|
273
|
+
# FIXME: Note that recalculations are being done here, which
|
|
274
|
+
# FIXME: are not DRY. Redo this properly later.
|
|
275
|
+
@pole[:cacc] = cacc = @cart[:acc] * -1.0
|
|
276
|
+
@pole[:force][:cradial] = radial = iRadial.basis(cacc * @pole[:mass])
|
|
277
|
+
# the magnitude of the radial vector goes to the torque on
|
|
278
|
+
@pole[:force][:ctorque] = torque = r.cross_product(radial)
|
|
279
|
+
@pole[:calpha] = alpha = torque / (@pole[:mass] * (@pole[:length] ** 2.0))
|
|
280
|
+
@pole[:cddang] = -alpha[Z] / TORAD # the pseudo vector component Z is the signed magnitude
|
|
281
|
+
@pole[:cdang] += @pole[:cddang] * @dt
|
|
282
|
+
@pole[:ang] += @pole[:cdang] * @dt
|
|
283
|
+
|
|
284
|
+
## Actual cart physics
|
|
285
|
+
@cart[:vel][X] += @cart[:acc][X] * @dt
|
|
286
|
+
@cart[:pos][X] += @cart[:vel][X] * @dt
|
|
287
|
+
@cart[:x] = @cart[:pos][X] * @pix_meters
|
|
288
|
+
@cart[:y] = @cart[:pos][Y] * @pix_meters
|
|
289
|
+
|
|
290
|
+
#puts '=' * 80
|
|
291
|
+
#pp({pole: @pole, cart: @cart})
|
|
292
|
+
|
|
293
|
+
# wheels physics -- angular velocity of each wheel based
|
|
294
|
+
# on the linear velocity of the cart.
|
|
295
|
+
@wheels.each do |w|
|
|
296
|
+
w[:dang] = 360.0 * @cart[:vel][X] / w[:circumference]
|
|
297
|
+
w[:ang] += w[:dang] * @dt
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# model update
|
|
301
|
+
self.update_cart
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# update the positions of all the compnents of the cart
|
|
305
|
+
# in terms of the relative positional relationships
|
|
306
|
+
def update_cart
|
|
307
|
+
# center of cart is taken as (x, y), actual is (_x, _y)
|
|
308
|
+
pw = @cart[:image].width * @cart[:scale]
|
|
309
|
+
ph = @cart[:image].height * @cart[:scale]
|
|
310
|
+
@cart[:_x] = @cart[:x] - pw / 2.0
|
|
311
|
+
@cart[:_y] = @cart[:y] - ph / 2.0
|
|
312
|
+
|
|
313
|
+
# Wheels in their respective places
|
|
314
|
+
@wheels.each do |wl|
|
|
315
|
+
#ww = wl[:image].width * wl[:scale]
|
|
316
|
+
#wh = wl[:image].height * wl[:scale]
|
|
317
|
+
wl[:_x] = @cart[:x] + wl[:xoff] * pw / 2.0
|
|
318
|
+
wl[:_y] = @cart[:y] + wl[:yoff] * ph / 2.0
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Pendulum
|
|
322
|
+
polew = @pole[:image].width * @pole[:scale]
|
|
323
|
+
poleh = @pole[:image].height * @pole[:scale]
|
|
324
|
+
@pole[:_x] = @cart[:x]
|
|
325
|
+
@pole[:_y] = @cart[:y]
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def draw
|
|
329
|
+
@pole[:image].draw_rot( @pole[:_x] % @pix_width,
|
|
330
|
+
@pole[:_y],
|
|
331
|
+
@pole[:z],
|
|
332
|
+
-@pole[:ang], # negative because y is inverted on the canvas
|
|
333
|
+
@pole[:xoff], @pole[:yoff],
|
|
334
|
+
@pole[:scale],
|
|
335
|
+
@pole[:scale])
|
|
336
|
+
|
|
337
|
+
@cart[:image].draw(@cart[:_x] % @pix_width,
|
|
338
|
+
@cart[:_y],
|
|
339
|
+
0,
|
|
340
|
+
@cart[:scale],
|
|
341
|
+
@cart[:scale])
|
|
342
|
+
|
|
343
|
+
@wheels.each do |wh|
|
|
344
|
+
wh[:image].draw_rot(wh[:_x] % @pix_width,
|
|
345
|
+
wh[:_y],
|
|
346
|
+
0,
|
|
347
|
+
wh[:ang],
|
|
348
|
+
0.5, 0.5,
|
|
349
|
+
wh[:scale],
|
|
350
|
+
wh[:scale])
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
module DSL
|
|
356
|
+
include Math
|
|
357
|
+
def invpend(&block)
|
|
358
|
+
@ipwin = InvPendWindow.new
|
|
359
|
+
|
|
360
|
+
def cart(&block)
|
|
361
|
+
@cart_params = block.()
|
|
362
|
+
unless @cart_params[:naked]
|
|
363
|
+
@cart = @ipwin.cart = Cart.new({ipwin: @ipwin}.merge @cart_params)
|
|
364
|
+
else
|
|
365
|
+
@cart = Cart.new(@cart_params)
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def show(cart: @cart, &block)
|
|
370
|
+
unless cart.nil?
|
|
371
|
+
@ipwin.cart = cart
|
|
372
|
+
cart.ipwin = @ipwin
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
@ipwin.show
|
|
376
|
+
end
|
|
377
|
+
block.(@ipwin)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
data/neater/rnlib/xor.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
=begin rdoc
|
|
2
|
+
Basic xor function we shall evolve a net for. Only goes true
|
|
3
|
+
on one and only one true input, false otherwise.
|
|
4
|
+
== Note Well
|
|
5
|
+
This function can either take 0 or -1 to signify "false".
|
|
6
|
+
=end
|
|
7
|
+
|
|
8
|
+
def xor(*inp)
|
|
9
|
+
inp.map{|n| (n > 0) ? 1 : 0}.reduce {|p, i| p + ((i > 0) ? 1 : 0) } == 1
|
|
10
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env neat
|
|
2
|
+
require 'rubyneat/dsl'
|
|
3
|
+
require 'xor'
|
|
4
|
+
|
|
5
|
+
include NEAT::DSL
|
|
6
|
+
|
|
7
|
+
#= DEBUGGING FOR RubyNEAT / Sigmoid
|
|
8
|
+
|
|
9
|
+
# The number of inputs to the xor function
|
|
10
|
+
XOR_INPUTS = 2
|
|
11
|
+
|
|
12
|
+
$log.level = Logger::DEBUG
|
|
13
|
+
|
|
14
|
+
# This defines the controller
|
|
15
|
+
define "XOR Sigmoid Debug System" do
|
|
16
|
+
# Define the IO neurons
|
|
17
|
+
inputs {
|
|
18
|
+
cinv = Hash[(1..XOR_INPUTS).map{|i| [("i%s" % i).to_sym, InputNeuron]}]
|
|
19
|
+
cinv[:bias] = BiasNeuron
|
|
20
|
+
cinv
|
|
21
|
+
}
|
|
22
|
+
outputs out: SigmoidNeuron
|
|
23
|
+
|
|
24
|
+
# Hidden neuron specification is optional.
|
|
25
|
+
# The name given here is largely meaningless, but may be useful as some sort
|
|
26
|
+
# of unique flag.
|
|
27
|
+
hidden sig: SigmoidNeuron
|
|
28
|
+
|
|
29
|
+
### Settings
|
|
30
|
+
## General
|
|
31
|
+
hash_on_fitness = false
|
|
32
|
+
start_population_size 30
|
|
33
|
+
population_size 30
|
|
34
|
+
max_generations 10000
|
|
35
|
+
max_population_history 10
|
|
36
|
+
|
|
37
|
+
## Evolver probabilities and SDs
|
|
38
|
+
# Perturbations
|
|
39
|
+
mutate_perturb_gene_weights_prob 0.100
|
|
40
|
+
mutate_perturb_gene_weights_sd 0.25
|
|
41
|
+
|
|
42
|
+
# Complete Change of weight
|
|
43
|
+
mutate_change_gene_weights_prob 0.001
|
|
44
|
+
mutate_change_gene_weights_sd 2.00
|
|
45
|
+
|
|
46
|
+
# Adding new neurons and genes
|
|
47
|
+
mutate_add_neuron_prob 0.20
|
|
48
|
+
mutate_add_gene_prob 0.20
|
|
49
|
+
|
|
50
|
+
# Switching genes on and off
|
|
51
|
+
mutate_gene_disable_prob 0.001
|
|
52
|
+
mutate_gene_reenable_prob 0.001
|
|
53
|
+
|
|
54
|
+
interspecies_mate_rate 0.03
|
|
55
|
+
mate_only_prob 0.10 #0.7
|
|
56
|
+
|
|
57
|
+
# Mating
|
|
58
|
+
survival_threshold 0.20 # top % allowed to mate in a species.
|
|
59
|
+
survival_mininum_per_species 4 # for small populations, we need SOMETHING to go on.
|
|
60
|
+
|
|
61
|
+
# Fitness costs
|
|
62
|
+
fitness_cost_per_neuron 0.01
|
|
63
|
+
fitness_cost_per_gene 0.01
|
|
64
|
+
|
|
65
|
+
# Speciation
|
|
66
|
+
compatibility_threshold 2.5
|
|
67
|
+
disjoint_coefficient 0.6
|
|
68
|
+
excess_coefficient 0.6
|
|
69
|
+
weight_coefficient 0.2
|
|
70
|
+
max_species 20
|
|
71
|
+
dropoff_age 15
|
|
72
|
+
smallest_species 5
|
|
73
|
+
|
|
74
|
+
# Sequencing
|
|
75
|
+
start_sequence_at 0
|
|
76
|
+
end_sequence_at 2 ** XOR_INPUTS - 1
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
evolve do
|
|
80
|
+
# This query shall return a vector result that will serve
|
|
81
|
+
# as the inputs to the critter.
|
|
82
|
+
query { |seq|
|
|
83
|
+
# We'll use the seq to create the xor sequences via
|
|
84
|
+
# the least signficant bits.
|
|
85
|
+
condition_boolean_vector (0 ... XOR_INPUTS).map{|i| (seq & (1 << i)) != 0}, :sigmoid
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Compare the fitness of two critters. We may choose a different ordering
|
|
89
|
+
# here.
|
|
90
|
+
compare {|f1, f2| f2 <=> f1 }
|
|
91
|
+
|
|
92
|
+
# Here we integrate the cost with the fitness.
|
|
93
|
+
cost { |fitvec, cost|
|
|
94
|
+
$log.debug ">>>>>>> fitvec #{fitvec} cost #{cost}"
|
|
95
|
+
(4 - (fitvec.reduce {|a,r| a+r} / fitvec.size.to_f)) ** 2.0 - cost
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fitness { |vin, vout, seq|
|
|
99
|
+
unless vout == :error
|
|
100
|
+
bin = uncondition_boolean_vector vin, :sigmoid
|
|
101
|
+
bout = uncondition_boolean_vector vout, :sigmoid
|
|
102
|
+
bactual = [xor(*vin)]
|
|
103
|
+
vactual = condition_boolean_vector bactual, :sigmoid
|
|
104
|
+
fit = (bout == bactual) ? 0.00 : 1.00
|
|
105
|
+
#simple_fitness_error(vout, vactual.map{|f| f * 0.50 })
|
|
106
|
+
bfit = (bout == bactual) ? 'T' : 'F'
|
|
107
|
+
$log.debug "(%s) Fitness bin=%s, bout=%s, bactual=%s, vout=%s, fit=%6.3f, seq=%s" % [bfit,
|
|
108
|
+
bin,
|
|
109
|
+
bout,
|
|
110
|
+
bactual,
|
|
111
|
+
vout,
|
|
112
|
+
fit,
|
|
113
|
+
seq]
|
|
114
|
+
fit
|
|
115
|
+
else
|
|
116
|
+
$log.debug "Error on #{vin} [#{seq}]"
|
|
117
|
+
1.0
|
|
118
|
+
end
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
stop_on_fitness {|fitness, c|
|
|
122
|
+
puts "*** Generation Run #{c.generation_num} ***\n\n"
|
|
123
|
+
fitness[:best] >= 15
|
|
124
|
+
}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
report do |rept|
|
|
128
|
+
$log.info "REPORT #{rept.to_yaml}"
|
|
129
|
+
exit unless rept[:fitness][:best] < 15.0
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# The block here is called upon the completion of each generation
|
|
133
|
+
run_engine do |c|
|
|
134
|
+
$log.info "******** Run of generation %s completed, history count %d ********" %
|
|
135
|
+
[c.generation_num, c.population_history.size]
|
|
136
|
+
end
|