wallace 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/Gemfile +14 -0
  2. data/README.md +12 -0
  3. data/Rakefile +52 -0
  4. data/VERSION +1 -0
  5. data/bin/.gitkeep +0 -0
  6. data/lib/analysers/fitness_distribution_analyser.rb +28 -0
  7. data/lib/analysers/init.rb +1 -0
  8. data/lib/core/analyser.rb +63 -0
  9. data/lib/core/breeder.rb +68 -0
  10. data/lib/core/breeding_graph.rb +59 -0
  11. data/lib/core/breeding_graph/init.rb +3 -0
  12. data/lib/core/breeding_graph/input_node.rb +55 -0
  13. data/lib/core/breeding_graph/node.rb +68 -0
  14. data/lib/core/breeding_graph/node_input.rb +6 -0
  15. data/lib/core/evaluator.rb +52 -0
  16. data/lib/core/evolver.rb +47 -0
  17. data/lib/core/exceptions.rb +6 -0
  18. data/lib/core/experiment.rb +22 -0
  19. data/lib/core/fitness.rb +8 -0
  20. data/lib/core/fraction.rb +7 -0
  21. data/lib/core/individual.rb +65 -0
  22. data/lib/core/logger.rb +5 -0
  23. data/lib/core/migrator.rb +6 -0
  24. data/lib/core/operator.rb +54 -0
  25. data/lib/core/population.rb +56 -0
  26. data/lib/core/selector.rb +43 -0
  27. data/lib/core/species.rb +52 -0
  28. data/lib/core/state.rb +29 -0
  29. data/lib/core/subpopulation.rb +53 -0
  30. data/lib/core/termination.rb +39 -0
  31. data/lib/distributions/gaussian_distribution.rb +60 -0
  32. data/lib/distributions/init.rb +3 -0
  33. data/lib/fitness/init.rb +1 -0
  34. data/lib/fitness/raw_fitness.rb +30 -0
  35. data/lib/loggers/csv_logger.rb +20 -0
  36. data/lib/loggers/init.rb +1 -0
  37. data/lib/loggers/mongo_logger.rb +5 -0
  38. data/lib/loggers/sqlite_logger.rb +5 -0
  39. data/lib/modules/ge/backus_naur_form.rb +125 -0
  40. data/lib/modules/ge/grammar_derivation.rb +30 -0
  41. data/lib/modules/ge/grammar_species.rb +29 -0
  42. data/lib/modules/ge/init.rb +5 -0
  43. data/lib/modules/init.rb +2 -0
  44. data/lib/modules/koza/builder.rb +48 -0
  45. data/lib/modules/koza/builder/full_builder.rb +92 -0
  46. data/lib/modules/koza/builder/grow_builder.rb +103 -0
  47. data/lib/modules/koza/builder/half_builder.rb +70 -0
  48. data/lib/modules/koza/builder/init.rb +3 -0
  49. data/lib/modules/koza/ephemeral.rb +33 -0
  50. data/lib/modules/koza/init.rb +12 -0
  51. data/lib/modules/koza/koza_node.rb +108 -0
  52. data/lib/modules/koza/koza_node_value.rb +72 -0
  53. data/lib/modules/koza/koza_node_value_set.rb +51 -0
  54. data/lib/modules/koza/koza_species.rb +48 -0
  55. data/lib/modules/koza/koza_tree.rb +159 -0
  56. data/lib/modules/koza/operators/init.rb +4 -0
  57. data/lib/modules/koza/operators/subtree_crossover_operation.rb +43 -0
  58. data/lib/modules/koza/operators/subtree_mutation_operation.rb +32 -0
  59. data/lib/operators/bit_flip_mutation_operation.rb +29 -0
  60. data/lib/operators/boundary_mutation_operation.rb +28 -0
  61. data/lib/operators/cycle_crossover_operation.rb +77 -0
  62. data/lib/operators/gaussian_mutation_operation.rb +39 -0
  63. data/lib/operators/half_uniform_crossover_operation.rb +24 -0
  64. data/lib/operators/init.rb +26 -0
  65. data/lib/operators/merging_crossover_operation.rb +27 -0
  66. data/lib/operators/one_point_crossover_operation.rb +29 -0
  67. data/lib/operators/order_crossover_operation.rb +38 -0
  68. data/lib/operators/partially_mapped_crossover_operation.rb +44 -0
  69. data/lib/operators/point_mutation_operation.rb +31 -0
  70. data/lib/operators/position_crossover_operation.rb +50 -0
  71. data/lib/operators/reverse_sequence_mutation_operation.rb +13 -0
  72. data/lib/operators/shuffle_mutation_operation.rb +17 -0
  73. data/lib/operators/splice_crossover_operation.rb +42 -0
  74. data/lib/operators/subtour_exchange_crossover_operation.rb +54 -0
  75. data/lib/operators/swap_mutation_operation.rb +29 -0
  76. data/lib/operators/three_parent_crossover_operation.rb +16 -0
  77. data/lib/operators/two_point_crossover_operation.rb +31 -0
  78. data/lib/operators/twors_mutation_operation.rb +18 -0
  79. data/lib/operators/uniform_crossover_operation.rb +30 -0
  80. data/lib/operators/uniform_mutation_operation.rb +31 -0
  81. data/lib/operators/variable_one_point_crossover_operation.rb +80 -0
  82. data/lib/patches/enumerable.rb +85 -0
  83. data/lib/patches/init.rb +5 -0
  84. data/lib/patches/range.rb +13 -0
  85. data/lib/selectors/init.rb +5 -0
  86. data/lib/selectors/random_selector.rb +14 -0
  87. data/lib/selectors/roulette_selector.rb +23 -0
  88. data/lib/selectors/tournament_selector.rb +36 -0
  89. data/lib/species/array_species.rb +40 -0
  90. data/lib/species/bit_string_species.rb +18 -0
  91. data/lib/species/init.rb +4 -0
  92. data/lib/species/permutation_species.rb +22 -0
  93. data/lib/species/string_species.rb +29 -0
  94. data/lib/utility/init.rb +4 -0
  95. data/lib/utility/scaled_array.rb +88 -0
  96. data/lib/utility/sorted_array.rb +39 -0
  97. data/lib/wallace.rb +40 -0
  98. data/test/.gitkeep +0 -0
  99. metadata +248 -0
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'peach'
4
+
5
+ # GraphViz - Great for Trees, Graph and Network visualisation.
6
+ #gem 'ruby-graphviz'
7
+ #gem 'win32-open3'
8
+
9
+ group :development do
10
+ gem 'jeweler', '~> 1.8.7'
11
+ gem 'rake'
12
+ gem 'rdoc'
13
+ gem 'bundler'
14
+ end
@@ -0,0 +1,12 @@
1
+ **Wallace.rb**
2
+ ==========
3
+
4
+ A highly expressive and modular evolutionary toolkit for performing genetic algorithms, genetic programming, grammatical evolution and meta-evolution in Ruby.
5
+
6
+ **Tested with:**
7
+ * Ruby >= 1.9.1
8
+ * JRuby >= 1.7.8
9
+
10
+ **Tested platforms:**
11
+ * Windows 7 (x64)
12
+ * Ubuntu 13.10 (x64)
@@ -0,0 +1,52 @@
1
+ # Load all dependencies.
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ require 'rdoc/task'
7
+ require 'jeweler'
8
+
9
+ begin
10
+ Bundler.setup(:default, :development)
11
+ rescue Bundler::BundlerError => e
12
+ $stderr.puts e.message
13
+ $stderr.puts "Run `bundle install` to install missing gems"
14
+ exit e.status_code
15
+ end
16
+
17
+ # Gem Specification.
18
+ Jeweler::Tasks.new do |gem|
19
+ gem.name = "wallace"
20
+ gem.homepage = "http://github.com/ChrisTimperley/Wallace.rb"
21
+ gem.license = "MIT"
22
+ gem.summary = "A powerful, flexible and modular toolkit for running Evolutionary Algorithms in Ruby"
23
+ gem.description = <<-EOF
24
+ Wallace is a powerful, flexible and modular toolkit for running Evolutionary Algorithms in Ruby.
25
+ Out of the box it provides support for steady-state EAs, genetic algorithms, genetic programming,
26
+ grammatical evolution and other types of EAs.
27
+ EOF
28
+ gem.email = "christimperley@gmail.com"
29
+ gem.author = "Chris Timperley"
30
+ gem.add_dependency "peach", "~> 0.5.1"
31
+ end
32
+
33
+ # Gem Management.
34
+ Jeweler::RubygemsDotOrgTasks.new
35
+
36
+ # Unit Testing.
37
+ Rake::TestTask.new(:test) do |test|
38
+ test.libs << 'lib' << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ end
42
+
43
+ # Documentation.
44
+ task :default => :test
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "wallace #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
File without changes
@@ -0,0 +1,28 @@
1
+ class Wallace::Analysers::FitnessDistributionAnalyser < Wallace::Analyser
2
+
3
+ def initialize
4
+
5
+ end
6
+
7
+ def after_generation(state)
8
+
9
+ end
10
+
11
+ protected
12
+
13
+ # Calculates the distribution of fitness values at the current evolution state.
14
+ #
15
+ # *Parameters:*
16
+ # * state, the current state of the evolution.
17
+ def calculate_distribution(state)
18
+ stats = {}
19
+ stats[:max] = state.population.fitness_max
20
+ stats[:min] = state.population.fitness_min
21
+ stats[:lq], stats[:median], stats[:uq] = state.population.fitness_quartiles
22
+ stats[:mean] = state.population.fitness_mean
23
+ stats[:std] =
24
+ stats[:var] =
25
+ return stats
26
+ end
27
+
28
+ end
@@ -0,0 +1 @@
1
+ module Wallace::Analysers; end
@@ -0,0 +1,63 @@
1
+ # Analysers are used to analyse the current state of the evolution at given stages.
2
+ # These objects may be used to gather data, calculate statistics and log information
3
+ # during the evolution.
4
+ #
5
+ # Analysers may harness the outputs of attached analysers to supplement their input data.
6
+ # This ability can be exploited to perform multi-stage post-processing and to efficiently
7
+ # record information.
8
+ class Wallace::Analyser
9
+
10
+ attr_reader :inputs
11
+
12
+ # Constructs a new analyser.
13
+ #
14
+ # *Parameters:*
15
+ # * inputs, the input analysers which feed data into this analyser.
16
+ def initialize(inputs)
17
+ @inputs = inputs
18
+ end
19
+
20
+ # Runs this analyser at a given stage in the evolution.
21
+ #
22
+ # Executes the input analysers to gather the input data which is then
23
+ # fed into the appropriate stage handler of this analyser.
24
+ #
25
+ # *Parameters:*
26
+ # * stage, the current stage in the evolution.
27
+ # * state, the current state of the evolution.
28
+ #
29
+ # *Returns:*
30
+ # Output data for processing by any attached analysers.
31
+ def run(stage, state)
32
+ input_data = @inputs.map { |i| i.run(stage, state) }
33
+ self.method(stage).invoke(state, input_data)
34
+ end
35
+
36
+ # All stage handlers are protected and should not be called directly!
37
+ # Instead the 'run' method must be used so that input data is gathered
38
+ # for the analyser.
39
+ protected
40
+
41
+ # This analysis hook is called prior to the start of each generation.
42
+ #
43
+ # *Parameters:*
44
+ # * state, the current state of the evolution.
45
+ # * input_data, the data provided by the attached input analysers.
46
+ def before_generation(state, input_data = nil); end
47
+
48
+ # This analysis hook is called after the end of a generation.
49
+ #
50
+ # *Parameters:*
51
+ # * state, the current state of the evolution.
52
+ # * input_data, the data provided by the attached input analysers.
53
+ def after_generation(state, input_data = nil); end
54
+
55
+ # This analysis hook is called upon termination of the evolution.
56
+ #
57
+ # *Parameters:*
58
+ # * state, the current state of the evolution.
59
+ # * input_data, the data provided by the attached input analysers.
60
+ def on_termination(state, input_data = nil); end
61
+ alias_method :after_run, :on_termination
62
+
63
+ end
@@ -0,0 +1,68 @@
1
+ #
2
+ #
3
+ # The breeder is decoupled from the evolver, subpopulation and population models.
4
+ # This allows the breeder to be used in a number of different configurations, where
5
+ # one breeder is used per evolver, population or sub-population.
6
+ class Wallace::Breeder
7
+
8
+ attr_reader :elitism,
9
+ :graph,
10
+ :threads
11
+
12
+ # Constructs a new breeder.
13
+ #
14
+ # *Arguments*
15
+ # * opts, a hash of keyword options for this method.
16
+ # -> graph, the breeding graph for this breeder.
17
+ # -> elitism, the number (or fraction) of fittest individuals that should be carried over to the
18
+ # next generation. (default = 0).
19
+ # -> threads, the number of threads the breeding process is split across. (default = 1).
20
+ def initialize(opts = {})
21
+ @elitism = opts[:elitism]
22
+ @threads = opts[:threads] || 1
23
+ @graphs = Array.new(@threads) { opts[:graph].clone }
24
+ end
25
+
26
+ # Breeds the next generation of individuals for the given subpopulation.
27
+ #
28
+ # *Parameters:*
29
+ # * rng, random number generation to use during breeding.
30
+ # * subpopulation, the target subpopulation.
31
+ def breed!(rng, subpopulation)
32
+
33
+ # Prepare the candidate list for each input for all graphs.
34
+ @graphs[0].inputs.each_index do |i|
35
+ candidates = subpopulation.contents
36
+ @graphs.each_index do |g|
37
+ candidates = @graphs[g].inputs[i].prepare!(candidates, random: rng, processed: g > 0)
38
+ end
39
+ end
40
+
41
+ # Create a temporary array for the new sub-population.
42
+ size = subpopulation.contents.size
43
+ buffer = Array.new(size)
44
+
45
+ # Add the elite individuals to the end of the sub-population if elitism is enabled.
46
+ elites = @elitism.nil? ? 0 : @elitism
47
+ elites = elites.value * size if elites.is_a? Wallace::Fraction
48
+ buffer[(size - elites)...size] = subpopulation.contents.nmin(elites)
49
+
50
+ # Spread the breeding process across multiple threads.
51
+ # using a separate breeding graph for each thread to ensure thread-safety.
52
+ thread_size = (size/@threads.to_f).ceil
53
+ (0...@threads).peach(@threads) do |t|
54
+ range = t * thread_size
55
+ range = range...([size, range + thread_size].min)
56
+
57
+ @graphs[t].breed!(rng, buffer, range)
58
+ end
59
+
60
+ # Clean each breeding graph.
61
+ @graphs.each { |g| g.clean! }
62
+
63
+ # Swap the contents of the sub-population with the buffer.
64
+ subpopulation.contents = buffer
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,59 @@
1
+ class Wallace::BreedingGraph
2
+
3
+ attr_reader :outputs,
4
+ :inputs,
5
+ :nodes
6
+
7
+ # Constructs a new BreedingGraph.
8
+ #
9
+ # *Parameters:*
10
+ # * opts, a hash of keyword options.
11
+ # -> outputs, an array of terminal nodes in this breeding graph (can be weighted).
12
+ # -> buffered, flag indicating whether the process should be buffered.
13
+ def initialize(opts = {})
14
+
15
+ @outputs = opts[:outputs]
16
+ @buffered = opts[:buffered] || true
17
+
18
+ # Produce a list of nodes in the graph and find all inputs to the graph.
19
+ @nodes = []
20
+ @inputs = []
21
+ queue = @outputs.clone
22
+
23
+ until queue.empty?
24
+ node = queue.shift
25
+ @nodes << node
26
+ if node.is_a? Wallace::BreedingGraph::InputNode
27
+ @inputs << node
28
+ else
29
+ queue += node.inputs.map{ |i| i.source }
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ # Discards all temporary information regarding the last breeding
36
+ # cycle and clears all the buffers.
37
+ def clean!
38
+ @nodes.each { |n| n.clean! }
39
+ end
40
+
41
+ # Breeds a portion of the associated given sub-population for the next generation.
42
+ #
43
+ # *Parameters:*
44
+ # * rng, the RNG to use when breeding individuals.
45
+ # * buffer, the buffer for the contents of the sub-population of the next generation.
46
+ # * range, the range of indices to be populated in the buffer by newly bred individuals.
47
+ def breed!(rng, buffer, range)
48
+ range.each { |i| buffer[i] = @outputs.sample(random: rng).take!(rng) }
49
+ end
50
+
51
+ # Creates a clone of this breeding graph.
52
+ def clone
53
+ Wallace::BreedingGraph.new(
54
+ outputs: @outputs.map { |n| n.clone },
55
+ buffered: @buffered
56
+ )
57
+ end
58
+
59
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'node.rb'
2
+ require_relative 'input_node.rb'
3
+ require_relative 'node_input.rb'
@@ -0,0 +1,55 @@
1
+ # Used to represent input nodes (i.e. sub-population selection nodes) in the
2
+ # breeding graph.
3
+ class Wallace::BreedingGraph::InputNode < Wallace::BreedingGraph::Node
4
+
5
+ # Constructs a new input node.
6
+ #
7
+ # *Parameters:*
8
+ # * selector, the selection method used by this input node.
9
+ def initialize(selector)
10
+ super(selector, [])
11
+ @candidates = []
12
+ end
13
+
14
+ alias :selector :function
15
+
16
+ # Selects a single individual from the list of candidates using the selection method
17
+ # associated with this node.
18
+ #
19
+ # *Parameters:*
20
+ # * rng, the RNG to use when selecting an individual from the list of candidates.
21
+ def take!(rng)
22
+ @function.produce(rng, @candidates).clone
23
+ end
24
+
25
+ # Prepares this input node for the next breeding cycle by supplying the contents
26
+ # of the sub-population and performing any necessary post-processing.
27
+ #
28
+ # To prevent redundant post-processing when using multiple threads, we can supply
29
+ # a prepared candidate list from the same input node from an other breeding graph.
30
+ #
31
+ # *Parameters:*
32
+ # * candidates, a list of (possibly post-processed) candidates for selection.
33
+ # * opts, a hash of keyword options for this method.
34
+ # -> random, the RNG to use when preparing the candidate list.
35
+ # -> processed, a flag indicating if this candidate list has already been post-processed.
36
+ #
37
+ # *Returns:*
38
+ # The prepared candidate list (so that it can be exploited by identical nodes in other graphs).
39
+ def prepare!(candidates, opts = {})
40
+ @candidates = opts[:processed] ? candidates.clone : @function.prepare(candidates, opts)
41
+ return @candidates
42
+ end
43
+
44
+ # Creates a clone of this node and its inputs.
45
+ def clone
46
+ Wallace::BreedingGraph::InputNode.new(@function)
47
+ end
48
+
49
+ # Clears the contents of the buffer and candidates list for this input node.
50
+ def clean!
51
+ super
52
+ @candidates.clear
53
+ end
54
+
55
+ end
@@ -0,0 +1,68 @@
1
+ # Represents a node within the breeding graph.
2
+ #
3
+ # Each node corresponds to a stage within the breeding process and is associated with
4
+ # a given operator or selection method which is used on the inputs to that node to produce
5
+ # some individuals for the next generation or for further processing by successive nodes in
6
+ # the graph.
7
+ class Wallace::BreedingGraph::Node
8
+
9
+ attr_reader :function,
10
+ :inputs
11
+
12
+ # Constructs a node for the breeding graph.
13
+ #
14
+ # *Parameters:*
15
+ # * function, the operator or selection method associated to this node.
16
+ # * inputs, an array of inputs to this node.
17
+ def initialize(function, inputs)
18
+ @inputs = inputs
19
+ @function = function
20
+ @buffer = []
21
+ end
22
+
23
+ # Takes and returns a single individual produced (or selected) by this node.
24
+ #
25
+ # If there are no individuals held in the buffer then a number are produced
26
+ # (or selected) using the operator (or selection method) attached to this node.
27
+ #
28
+ # *Parameters:*
29
+ # * rng, the RNG to use if new individuals are bred.
30
+ #
31
+ # *Returns:*
32
+ # An array of individuals produced at this node.
33
+ def take!(rng)
34
+ @buffer += @function.produce(rng, generate_inputs!(rng)) if @buffer.empty?
35
+ return @buffer.pop
36
+ end
37
+
38
+ # Clears the buffer of this node and discards any temporary
39
+ # information relating to the breeding processs.
40
+ def clean!
41
+ @buffer.clear
42
+ end
43
+
44
+ # Creates a clone of this node and its inputs.
45
+ def clone
46
+ Wallace::BreedingGraph::Node.new(
47
+ @function,
48
+ @inputs.map { |i| Wallace::BreedingGraph::NodeInput.new(i.source.clone, i.size) }
49
+ )
50
+ end
51
+
52
+ protected
53
+
54
+ # Generates a set of individuals to use as input to this node using the information
55
+ # in the list of associated node inputs.
56
+ #
57
+ # *Parameters:*
58
+ # * rng, the RNG to use when producing individuals up the breeding chain.
59
+ #
60
+ # *Returns:*
61
+ # An array of individuals to use as input for this node.
62
+ def generate_inputs!(rng)
63
+ return @inputs.reduce([]) do |inds, input|
64
+ inds += Array.new(input.size) { input.source.take!(rng) }
65
+ end
66
+ end
67
+
68
+ end
@@ -0,0 +1,6 @@
1
+ # Used to represent inputs to a given node in the breeding graph.
2
+ #
3
+ # *Attributes:*
4
+ # * source, the source node to retrieve individuals from.
5
+ # * size, the number of individuals to retrieve from the source.
6
+ Wallace::BreedingGraph::NodeInput = Struct.new(:source, :size)