wallace 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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)