wallace 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|