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.
- data/Gemfile +14 -0
- data/README.md +12 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/bin/.gitkeep +0 -0
- data/lib/analysers/fitness_distribution_analyser.rb +28 -0
- data/lib/analysers/init.rb +1 -0
- data/lib/core/analyser.rb +63 -0
- data/lib/core/breeder.rb +68 -0
- data/lib/core/breeding_graph.rb +59 -0
- data/lib/core/breeding_graph/init.rb +3 -0
- data/lib/core/breeding_graph/input_node.rb +55 -0
- data/lib/core/breeding_graph/node.rb +68 -0
- data/lib/core/breeding_graph/node_input.rb +6 -0
- data/lib/core/evaluator.rb +52 -0
- data/lib/core/evolver.rb +47 -0
- data/lib/core/exceptions.rb +6 -0
- data/lib/core/experiment.rb +22 -0
- data/lib/core/fitness.rb +8 -0
- data/lib/core/fraction.rb +7 -0
- data/lib/core/individual.rb +65 -0
- data/lib/core/logger.rb +5 -0
- data/lib/core/migrator.rb +6 -0
- data/lib/core/operator.rb +54 -0
- data/lib/core/population.rb +56 -0
- data/lib/core/selector.rb +43 -0
- data/lib/core/species.rb +52 -0
- data/lib/core/state.rb +29 -0
- data/lib/core/subpopulation.rb +53 -0
- data/lib/core/termination.rb +39 -0
- data/lib/distributions/gaussian_distribution.rb +60 -0
- data/lib/distributions/init.rb +3 -0
- data/lib/fitness/init.rb +1 -0
- data/lib/fitness/raw_fitness.rb +30 -0
- data/lib/loggers/csv_logger.rb +20 -0
- data/lib/loggers/init.rb +1 -0
- data/lib/loggers/mongo_logger.rb +5 -0
- data/lib/loggers/sqlite_logger.rb +5 -0
- data/lib/modules/ge/backus_naur_form.rb +125 -0
- data/lib/modules/ge/grammar_derivation.rb +30 -0
- data/lib/modules/ge/grammar_species.rb +29 -0
- data/lib/modules/ge/init.rb +5 -0
- data/lib/modules/init.rb +2 -0
- data/lib/modules/koza/builder.rb +48 -0
- data/lib/modules/koza/builder/full_builder.rb +92 -0
- data/lib/modules/koza/builder/grow_builder.rb +103 -0
- data/lib/modules/koza/builder/half_builder.rb +70 -0
- data/lib/modules/koza/builder/init.rb +3 -0
- data/lib/modules/koza/ephemeral.rb +33 -0
- data/lib/modules/koza/init.rb +12 -0
- data/lib/modules/koza/koza_node.rb +108 -0
- data/lib/modules/koza/koza_node_value.rb +72 -0
- data/lib/modules/koza/koza_node_value_set.rb +51 -0
- data/lib/modules/koza/koza_species.rb +48 -0
- data/lib/modules/koza/koza_tree.rb +159 -0
- data/lib/modules/koza/operators/init.rb +4 -0
- data/lib/modules/koza/operators/subtree_crossover_operation.rb +43 -0
- data/lib/modules/koza/operators/subtree_mutation_operation.rb +32 -0
- data/lib/operators/bit_flip_mutation_operation.rb +29 -0
- data/lib/operators/boundary_mutation_operation.rb +28 -0
- data/lib/operators/cycle_crossover_operation.rb +77 -0
- data/lib/operators/gaussian_mutation_operation.rb +39 -0
- data/lib/operators/half_uniform_crossover_operation.rb +24 -0
- data/lib/operators/init.rb +26 -0
- data/lib/operators/merging_crossover_operation.rb +27 -0
- data/lib/operators/one_point_crossover_operation.rb +29 -0
- data/lib/operators/order_crossover_operation.rb +38 -0
- data/lib/operators/partially_mapped_crossover_operation.rb +44 -0
- data/lib/operators/point_mutation_operation.rb +31 -0
- data/lib/operators/position_crossover_operation.rb +50 -0
- data/lib/operators/reverse_sequence_mutation_operation.rb +13 -0
- data/lib/operators/shuffle_mutation_operation.rb +17 -0
- data/lib/operators/splice_crossover_operation.rb +42 -0
- data/lib/operators/subtour_exchange_crossover_operation.rb +54 -0
- data/lib/operators/swap_mutation_operation.rb +29 -0
- data/lib/operators/three_parent_crossover_operation.rb +16 -0
- data/lib/operators/two_point_crossover_operation.rb +31 -0
- data/lib/operators/twors_mutation_operation.rb +18 -0
- data/lib/operators/uniform_crossover_operation.rb +30 -0
- data/lib/operators/uniform_mutation_operation.rb +31 -0
- data/lib/operators/variable_one_point_crossover_operation.rb +80 -0
- data/lib/patches/enumerable.rb +85 -0
- data/lib/patches/init.rb +5 -0
- data/lib/patches/range.rb +13 -0
- data/lib/selectors/init.rb +5 -0
- data/lib/selectors/random_selector.rb +14 -0
- data/lib/selectors/roulette_selector.rb +23 -0
- data/lib/selectors/tournament_selector.rb +36 -0
- data/lib/species/array_species.rb +40 -0
- data/lib/species/bit_string_species.rb +18 -0
- data/lib/species/init.rb +4 -0
- data/lib/species/permutation_species.rb +22 -0
- data/lib/species/string_species.rb +29 -0
- data/lib/utility/init.rb +4 -0
- data/lib/utility/scaled_array.rb +88 -0
- data/lib/utility/sorted_array.rb +39 -0
- data/lib/wallace.rb +40 -0
- data/test/.gitkeep +0 -0
- metadata +248 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# The evaluator is responsible for determining the fitness of given individuals within the
|
|
2
|
+
# population. An evaluation function is provided to each evaluator which produces a fitness
|
|
3
|
+
# measure object for a given individual.
|
|
4
|
+
class Wallace::Evaluator
|
|
5
|
+
|
|
6
|
+
attr_reader :threads
|
|
7
|
+
|
|
8
|
+
# Constructs a new evaluator.
|
|
9
|
+
# Attach the given fitness calculation method to the evaluate method of this
|
|
10
|
+
# evaluator.
|
|
11
|
+
#
|
|
12
|
+
# *Parameters:*
|
|
13
|
+
# * opts, a hash of keyword options for this evaluator.
|
|
14
|
+
# -> threads, the number of threads that evaluation should be split across.
|
|
15
|
+
# * f, function to calculate and return the fitness of a given individual.
|
|
16
|
+
def initialize(opts = {}, &f)
|
|
17
|
+
@threads = opts[:threads] || 1
|
|
18
|
+
define_singleton_method(:evaluate, &f)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Evaluates all given individuals within a population.
|
|
22
|
+
# If multi-threading is enabled then individuals are split into equal (as possible)
|
|
23
|
+
# chunks. For now concurrency has not been implemented, and will be thought about
|
|
24
|
+
# in more detail in a future version.
|
|
25
|
+
#
|
|
26
|
+
# *Parameters:*
|
|
27
|
+
# * rng, random number generator to use during evaluation.
|
|
28
|
+
# * population, the population of individuals to evaluate.
|
|
29
|
+
def process!(rng, population)
|
|
30
|
+
population.subpopulations.each do |s|
|
|
31
|
+
if @threads > 1
|
|
32
|
+
s.contents.peach(@threads) { |i| i.fitness = evaluate(rng, i) }
|
|
33
|
+
else
|
|
34
|
+
s.contents.each { |i| i.fitness = evaluate(rng, i) }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Should we find the best and worst individuals in each sub-population?
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Evaluates a given individual and returns their fitness score.
|
|
43
|
+
# Should not modify the providied individual.
|
|
44
|
+
#
|
|
45
|
+
# *Parameters:*
|
|
46
|
+
# * rng, random number generator to use during evaluation.
|
|
47
|
+
# * individual, the individual whose fitness should be calculated.
|
|
48
|
+
def evaluate(rng, individual)
|
|
49
|
+
raise NotImplementedError, 'No evaluation function was provided to this evaluator.'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
data/lib/core/evolver.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Steady-state vs. Generational
|
|
2
|
+
class Wallace::Evolver
|
|
3
|
+
|
|
4
|
+
# Constructs a new evolver.
|
|
5
|
+
#
|
|
6
|
+
# *Parameters:*
|
|
7
|
+
# * rng, the random number generator to use for stochastic processes.
|
|
8
|
+
# * population, the population to evolve.
|
|
9
|
+
# * evaluator, the evaluator to use to determine the fitness of individuals.
|
|
10
|
+
# * breeder, the breeder to use to create individuals for successive generations.
|
|
11
|
+
# * migrator, the migrator to use to exchange individuals between sub-populations.
|
|
12
|
+
# * termination, the termination criteria for the evolution.
|
|
13
|
+
def initialize(rng, population, evaluator, termination)
|
|
14
|
+
@rng = rng
|
|
15
|
+
@population = population
|
|
16
|
+
@evaluator = evaluator
|
|
17
|
+
@termination = termination
|
|
18
|
+
@evaluator = evaluator
|
|
19
|
+
@state = nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Conducts the described evolutionary algorithm until the termination criteria is met.
|
|
23
|
+
# Upon meeting the termination criteria, the best individual found from the entire run
|
|
24
|
+
# is returned.
|
|
25
|
+
def evolve
|
|
26
|
+
|
|
27
|
+
# Initialise and evaluate the population.
|
|
28
|
+
@population.fresh!(@rng)
|
|
29
|
+
@evaluator.process!(@rng, @population)
|
|
30
|
+
@state = Wallace::State.new(@population)
|
|
31
|
+
|
|
32
|
+
# Continue the evolution unless the termination condition has been met.
|
|
33
|
+
until @termination.finished?(@state)
|
|
34
|
+
@migrator.migrate!(@rng, @population) unless @migrator.nil?
|
|
35
|
+
@population.breed!(@rng)
|
|
36
|
+
@evaluator.process!(@rng, @population)
|
|
37
|
+
@state.next!
|
|
38
|
+
#puts "#{@state.best.to_s} = #{@state.best.fitness.value}"
|
|
39
|
+
puts "#{@state.generations}: #{@state.best.fitness.value} (#{@state.best.data.length})"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Return the best individual from the run.
|
|
43
|
+
return @state.best
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Experiment instances are used to
|
|
2
|
+
class Wallace::Experiment
|
|
3
|
+
|
|
4
|
+
# Constructs a new experiment.
|
|
5
|
+
#
|
|
6
|
+
# *Parameters:*
|
|
7
|
+
# * opts, a hash of keyword options for this constructor.
|
|
8
|
+
# -> parameters, the set of parameters to feed to the configurator.
|
|
9
|
+
# -> repeats, the number of times to repeat the experiment.
|
|
10
|
+
# * configurator, a lambda function used to setup the experiment run according to
|
|
11
|
+
# some given parameters.
|
|
12
|
+
def initialize(opts, configurator)
|
|
13
|
+
@parameters = opts[:parameters]
|
|
14
|
+
@repeats = opts[:repeats] || 1
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Performs the experiment described by this objects attributes.
|
|
18
|
+
def experiment
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
data/lib/core/fitness.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# The base fitness measure class. Fitness objects are responsible for storing
|
|
2
|
+
# fitness details for a given individual and should implement ordering
|
|
3
|
+
# functionality such that they can be compared and sorted.
|
|
4
|
+
class Wallace::Fitness
|
|
5
|
+
|
|
6
|
+
include Comparable
|
|
7
|
+
|
|
8
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Instances of the fraction class are used to disambiguate if a given float
|
|
2
|
+
# should be treated as an absolute value or rather a fraction of some other
|
|
3
|
+
# (implicit) value.
|
|
4
|
+
#
|
|
5
|
+
# If the Fraction class is not used, it is assumed that a given number is an
|
|
6
|
+
# absolute number (in a context-sensitive environment).
|
|
7
|
+
Wallace::Fraction = Struct.new(:value)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# This class is the base class used to represent individuals within the population.
|
|
2
|
+
# The data (e.g. list, tree, string) for an individual is held within its data attribute.
|
|
3
|
+
class Wallace::Individual
|
|
4
|
+
|
|
5
|
+
include Comparable
|
|
6
|
+
|
|
7
|
+
# Neither the species nor the data of the individual may be modified
|
|
8
|
+
# once the individual has been created.
|
|
9
|
+
attr_accessor :species,
|
|
10
|
+
:data
|
|
11
|
+
|
|
12
|
+
# Allow the fitness of the individual to be both read and written to.
|
|
13
|
+
attr_accessor :fitness
|
|
14
|
+
|
|
15
|
+
# Constructs a new individual.
|
|
16
|
+
#
|
|
17
|
+
# *Parameters:*
|
|
18
|
+
# * species, the species of the individual.
|
|
19
|
+
# * data, the data for this individual.
|
|
20
|
+
# * opts, keyword arguments for this constructor.
|
|
21
|
+
# * -> fitness, the fitness object for this individual (keyword).
|
|
22
|
+
def initialize(species, data, opts = {})
|
|
23
|
+
@species = species
|
|
24
|
+
@fitness = nil
|
|
25
|
+
@data = data
|
|
26
|
+
@fitness = opts[:fitness]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Checks whether this individual has been evaluated.
|
|
30
|
+
# Returns true if it has, false if otherwise.
|
|
31
|
+
def evaluated?
|
|
32
|
+
return (not @fitness.nil?)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Post-processes this individual.
|
|
36
|
+
# Returns the post-processed individual.
|
|
37
|
+
def finish!
|
|
38
|
+
@species.finish!(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Compares the fitness of this individual against that of another.
|
|
42
|
+
#
|
|
43
|
+
# *Parameters:*
|
|
44
|
+
# * other, the individual to compare against.
|
|
45
|
+
def <=>(other)
|
|
46
|
+
@fitness <=> other.fitness
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Creates a clone of this individual.
|
|
50
|
+
#
|
|
51
|
+
# *Parameters:*
|
|
52
|
+
# * opts, keyword arguments for this method.
|
|
53
|
+
# * -> copy_fitness, flag indicating whether fitness information should be copied across
|
|
54
|
+
# to the cloned individual.
|
|
55
|
+
def clone(opts = {})
|
|
56
|
+
copy_fitness = opts[:copy_fitness]
|
|
57
|
+
return Wallace::Individual.new(species, data.clone, fitness: copy_fitness ? fitness : nil)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Produces a string representation of this individual.
|
|
61
|
+
def to_s
|
|
62
|
+
return @data.to_s
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
data/lib/core/logger.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Operators are used to produce individuals for the next generation using
|
|
2
|
+
# members of the current population as their inputs.
|
|
3
|
+
#
|
|
4
|
+
# TODO: Feed state data into the operator (size of population, fitness, generations, etc).
|
|
5
|
+
class Wallace::Operator
|
|
6
|
+
|
|
7
|
+
# Using meta-methods to give the operator a name/tag that
|
|
8
|
+
# can be used to refer to it within the DSL or command line.
|
|
9
|
+
class << self
|
|
10
|
+
attr_accessor :name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Constructs an instance of an Operator.
|
|
14
|
+
#
|
|
15
|
+
# *Parameters:*
|
|
16
|
+
# * opts, a hash of keyword options for this method.
|
|
17
|
+
# -> id, the unique identifier for this operator.
|
|
18
|
+
def initialize(opts = {})
|
|
19
|
+
@id = opts[:id]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Produces an arbitrary number of individuals according to the rules of this operator
|
|
23
|
+
# using
|
|
24
|
+
#
|
|
25
|
+
# *Parameters:*
|
|
26
|
+
# * rng, random number generator to use within the operation.
|
|
27
|
+
# * inputs, input individuals to the operation.
|
|
28
|
+
#
|
|
29
|
+
# *Returns:*
|
|
30
|
+
# An array of the offspring individuals produced by this operation.
|
|
31
|
+
def produce(rng, inputs)
|
|
32
|
+
operate(rng, inputs.map { |i| i.data }).each_with_index do |data, i|
|
|
33
|
+
inputs[i].data = data
|
|
34
|
+
end
|
|
35
|
+
return inputs
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Performs this genetic operation on the genetic data of a given number of individuals
|
|
39
|
+
# to return the genetic data for their offspring.
|
|
40
|
+
#
|
|
41
|
+
# Unlike 'produce', this method operates only on the genetic data (we refrain from the
|
|
42
|
+
# term chromosome since an individual may have multiple chromosomes).
|
|
43
|
+
#
|
|
44
|
+
# *Parameters:*
|
|
45
|
+
# * rng, the RNG to use within this operation.
|
|
46
|
+
# * inputs, input individuals to the operation.
|
|
47
|
+
#
|
|
48
|
+
# *Returns:*
|
|
49
|
+
# An array containing the genetic data for each produced offspring.
|
|
50
|
+
def operate(rng, inputs)
|
|
51
|
+
raise NotImplementedError, "No 'operate' function was implemented by this operator."
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# In this current version of Wallace each population may only hold individuals of a single
|
|
2
|
+
# species. For future versions supporting co-operative and competitive evolution it should
|
|
3
|
+
# be able to adapt the population model to fit.
|
|
4
|
+
class Wallace::Population
|
|
5
|
+
|
|
6
|
+
attr_reader :subpopulations
|
|
7
|
+
|
|
8
|
+
# Constructs a new population.
|
|
9
|
+
#
|
|
10
|
+
# *Parameters:*
|
|
11
|
+
# * breeder, the breeder used to generate individuals for successive generations.
|
|
12
|
+
# * subpopulations, a list of subpopulations contained within this population.
|
|
13
|
+
def initialize(breeder, subpopulations)
|
|
14
|
+
@breeder = breeder
|
|
15
|
+
@subpopulations = subpopulations
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Clears the contents of each sub-population within this population and resets all
|
|
19
|
+
# attached components.
|
|
20
|
+
def clear!
|
|
21
|
+
@subpopulations.each { |s| s.clear }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Initialises a fresh population of individuals.
|
|
25
|
+
#
|
|
26
|
+
# *Parameters:*
|
|
27
|
+
# * rng, the random number generator to use.
|
|
28
|
+
def fresh!(rng)
|
|
29
|
+
@subpopulations.each { |s| s.fresh!(rng) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Breeds the next generation of individuals for this population.
|
|
33
|
+
#
|
|
34
|
+
# *Parameters:*
|
|
35
|
+
# * rng, random number generator to use during breeding.
|
|
36
|
+
def breed!(rng)
|
|
37
|
+
@subpopulations.each { |s| @breeder.breed!(rng, s) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Selects the best individual from the current population.
|
|
41
|
+
def best
|
|
42
|
+
@subpopulations.map { |s| s.best }.min
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Selects the worst individual from the current population.
|
|
46
|
+
def worst
|
|
47
|
+
@subpopulations.map { |s| s.worst }.max
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Calculates the combined size (number of individuals) of this population.
|
|
51
|
+
def size
|
|
52
|
+
@subpopulations.reduce(0) { |sum, sp| sum += sp.length }
|
|
53
|
+
end
|
|
54
|
+
alias_method :length, :size
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Selectors are used to select individuals from a set of candidates (usually, but not exclusively
|
|
2
|
+
# the sub-population) as participants in the breeding process.
|
|
3
|
+
#
|
|
4
|
+
# Different selector classes are used to implement different types of selection rules.
|
|
5
|
+
#
|
|
6
|
+
# A "prepare" method is provided to allow the list of candidates to be pre-processed, saving time
|
|
7
|
+
# for selection methods such as roulette selection.
|
|
8
|
+
class Wallace::Selector
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Prepares a list of candidates for use with this selector.
|
|
15
|
+
# Pre-processing can be performed on this list to improve performance.
|
|
16
|
+
# The list of candidates is not stored by the selector, instead it is stored
|
|
17
|
+
# by an associated input node.
|
|
18
|
+
#
|
|
19
|
+
# *Parameters:*
|
|
20
|
+
# * candidates, the list of candidates to select from.
|
|
21
|
+
# * opts, a hash of keyword options for this method.
|
|
22
|
+
# -> random, random number generator to use in pre-processing of candidates.
|
|
23
|
+
#
|
|
24
|
+
# *Returns:*
|
|
25
|
+
# A prepared list of candidates for use with this selector.
|
|
26
|
+
def prepare(candidates, opts = {})
|
|
27
|
+
candidates
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Selects a single individual from the list of prepared candidates according
|
|
31
|
+
# to the rules of this selection method.
|
|
32
|
+
#
|
|
33
|
+
# *Parameters:*
|
|
34
|
+
# * rng, the RNG to use to inform the choice of candidate.
|
|
35
|
+
# * candidates, the candidate individuals for selection.
|
|
36
|
+
#
|
|
37
|
+
# *Returns:*
|
|
38
|
+
# A selected individual from the list of candidates.
|
|
39
|
+
def produce(rng, candidates)
|
|
40
|
+
raise NotImplementedError, 'No produce function was implemented by this selector.'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
data/lib/core/species.rb
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Each individual in the population must belong to a single species.
|
|
2
|
+
class Wallace::Species
|
|
3
|
+
|
|
4
|
+
attr_reader :id
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :name
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Creates a new Species.
|
|
11
|
+
#
|
|
12
|
+
# *Parameters:*
|
|
13
|
+
# * opts, hash of keyword options used by this method.
|
|
14
|
+
# -> id, the unique identifier for this species.
|
|
15
|
+
def initialize(opts)
|
|
16
|
+
@id = opts[:id]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Determines whether a given individual is a valid member of this species.
|
|
20
|
+
# Validity may be determined by more than just membership. For example,
|
|
21
|
+
# there may be certain size constraints on individuals.
|
|
22
|
+
#
|
|
23
|
+
# *Parameters:*
|
|
24
|
+
# * individual, the individual to check for validity.
|
|
25
|
+
#
|
|
26
|
+
# *Returns:*
|
|
27
|
+
# true if a valid member of this species, false if invalid or not a member.
|
|
28
|
+
def valid?(individual)
|
|
29
|
+
individual.species === self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Spawns a new member of this species at random.
|
|
33
|
+
#
|
|
34
|
+
# *Parameters:*
|
|
35
|
+
# * rng, the random number generator to use.
|
|
36
|
+
def spawn(rng)
|
|
37
|
+
raise NotImplementedError, 'Spawn method not implemented by this species.'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Used to post-process individuals belonging to this species after they have
|
|
41
|
+
# been created. By default this method is a stub.
|
|
42
|
+
#
|
|
43
|
+
# *Parameters:*
|
|
44
|
+
# * individual, the individual to post-process.
|
|
45
|
+
#
|
|
46
|
+
# *Returns:*
|
|
47
|
+
# * the post-processed individual.
|
|
48
|
+
def finish!(individual)
|
|
49
|
+
individual
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
data/lib/core/state.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# This class is used to record information about the state of the evolution.
|
|
2
|
+
class Wallace::State
|
|
3
|
+
|
|
4
|
+
# Allow all information to be read, but not changed.
|
|
5
|
+
attr_reader :population,
|
|
6
|
+
:generations,
|
|
7
|
+
:stagnation,
|
|
8
|
+
:best
|
|
9
|
+
|
|
10
|
+
# Constructs a new state object.
|
|
11
|
+
#
|
|
12
|
+
# *Parameters*
|
|
13
|
+
# * population, the population of the state.
|
|
14
|
+
def initialize(population)
|
|
15
|
+
@population = population
|
|
16
|
+
@generations = 0
|
|
17
|
+
@stagnation = 0
|
|
18
|
+
@best = population.best
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Updates the state object with the current state of the evolver.
|
|
22
|
+
def next!
|
|
23
|
+
@generations += 1
|
|
24
|
+
@stagnation += 1
|
|
25
|
+
pbest = population.best
|
|
26
|
+
@best = pbest if pbest < @best
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|