Class: Evolvable::Population

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/evolvable/population.rb

Overview

Population objects are responsible for generating and evolving instances. They orchestrate all the other Evolvable objects to do so.

Populations can be initialized and re-initialized with a number of useful parameters.

Examples:

# TODO: initialize a population with all supported parameters

Constant Summary collapse

DUMP_METHODS =
%i[evolvable_type
id
name
size
evolutions_count
search_space
evolution
evaluation].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(evolvable_type: nil, evolvable_class: nil, id: nil, name: nil, size: 40, evolutions_count: 0, gene_space: nil, search_space: nil, parent_evolvables: [], evaluation: Evaluation.new, evolution: Evolution.new, selection: nil, combination: nil, mutation: nil, evolvables: []) ⇒ Population

Initializes an Evolvable::Population. Keyword arguments:

evolvable_class

Required. Implicitly specified when using EvolvableClass.new_population.

id, name

Both default to nil. Not used by Evolvable, but convenient when working with multiple populations.

size

Defaults to 40. Specifies the number of instances in the population.

evolutions_count

Defaults to 0. Useful when re-initializing a saved population with instances.

search_space

Defaults to evolvable_class.new_search_space which uses the EvolvableClass.search_space method

evolution

Defaults to Evolvable::Evolution.new. See evolution

evaluation

Defaults to Evolvable::Evaluation.new, with a goal of maximizing towards Float::INFINITY. See evaluation

instances

Defaults to initializing a size number of evolvable_class instances using the search_space object. Any given instances are assigned, but if given less than size, more will be initialized.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/evolvable/population.rb', line 46

def initialize(evolvable_type: nil,
               evolvable_class: nil, # Deprecated
               id: nil,
               name: nil,
               size: 40,
               evolutions_count: 0,
               gene_space: nil, # Deprecated
               search_space: nil,
               parent_evolvables: [],
               evaluation: Evaluation.new,
               evolution: Evolution.new,
               selection: nil,
               combination: nil,
               mutation: nil,
               evolvables: [])
  @id = id
  @evolvable_type = evolvable_type || evolvable_class
  @name = name
  @size = size
  @evolutions_count = evolutions_count
  @search_space = initialize_search_space(search_space || gene_space)
  @parent_evolvables = parent_evolvables
  self.evaluation = evaluation
  @evolution = evolution
  self.selection = selection if selection
  self.combination = combination if combination
  self.mutation = mutation if mutation
  @evolvables = new_evolvables(count: @size - evolvables.count, evolvables: evolvables)
end

Instance Attribute Details

#evaluationObject

Returns the value of attribute evaluation.



107
108
109
# File 'lib/evolvable/population.rb', line 107

def evaluation
  @evaluation
end

#evolutionObject

Returns the value of attribute evolution.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def evolution
  @evolution
end

#evolutions_countObject

Returns the value of attribute evolutions_count.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def evolutions_count
  @evolutions_count
end

#evolvable_typeObject

Returns the value of attribute evolvable_type.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def evolvable_type
  @evolvable_type
end

#evolvablesObject

Returns the value of attribute evolvables.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def evolvables
  @evolvables
end

#idObject

Returns the value of attribute id.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def id
  @id
end

#nameObject

Returns the value of attribute name.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def name
  @name
end

#parent_evolvablesObject

Returns the value of attribute parent_evolvables.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def parent_evolvables
  @parent_evolvables
end

#search_spaceObject

Returns the value of attribute search_space.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def search_space
  @search_space
end

#sizeObject

Returns the value of attribute size.



76
77
78
# File 'lib/evolvable/population.rb', line 76

def size
  @size
end

Class Method Details

.load(data) ⇒ Object



17
18
19
20
# File 'lib/evolvable/population.rb', line 17

def self.load(data)
  dump_attrs = Serializer.load(data)
  new(**dump_attrs)
end

Instance Method Details

#best_evolvableObject



161
162
163
# File 'lib/evolvable/population.rb', line 161

def best_evolvable
  evaluation.best_evolvable(self)
end

#dump(only: nil, except: nil) ⇒ Object



203
204
205
# File 'lib/evolvable/population.rb', line 203

def dump(only: nil, except: nil)
  Serializer.dump(dump_attrs(only: only, except: except))
end

#dump_attrs(only: nil, except: nil) ⇒ Object



216
217
218
219
220
221
222
# File 'lib/evolvable/population.rb', line 216

def dump_attrs(only: nil, except: nil)
  attrs = {}
  dump_methods = only || DUMP_METHODS
  dump_methods -= except if except
  dump_methods.each { |m| attrs[m] = send(m) }
  attrs
end

#evolvable_classObject



199
200
201
# File 'lib/evolvable/population.rb', line 199

def evolvable_class
  @evolvable_class ||= evolvable_type.is_a?(Class) ? evolvable_type : Object.const_get(evolvable_type)
end

#evolve(count: Float::INFINITY, goal_value: nil) ⇒ Object

Keyword arguments:

#### count The number of evolutions to run. Expects a positive integer and Defaults to Float::INFINITY and will therefore run indefinitely unless a goal_value is specified. #### goal_value Assigns the goal object's value. Will continue running until any instance's value reaches it. See evaluation

### Evolvable::Population#best_instance Returns an instance with the value that is nearest to the goal value.

### Evolvable::Population#met_goal? Returns true if any instance's value matches the goal value, otherwise false.

### Evolvable::Population#new_instance Initializes an instance for the population. Note that this method does not add the new instance to its array of instances.

Keyword arguments:

#### genes An array of initialized gene objects. Defaults to [] #### population_index Defaults to nil and expects an integer.

See (EvolvableClass#population_index)[#evolvableclasspopulation_index-population_index]



147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/evolvable/population.rb', line 147

def evolve(count: Float::INFINITY, goal_value: nil)
  goal.value = goal_value if goal_value
  1.upto(count) do
    before_evaluation(self)
    evaluation.call(self)
    before_evolution(self)
    break if met_goal?

    evolution.call(self)
    self.evolutions_count += 1
    after_evolution(self)
  end
end

#met_goal?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/evolvable/population.rb', line 165

def met_goal?
  evaluation.met_goal?(self)
end

#new_evolvable(genome: nil) ⇒ Object



169
170
171
172
173
174
175
176
177
# File 'lib/evolvable/population.rb', line 169

def new_evolvable(genome: nil)
  return generate_evolvables(1).first unless genome || parent_evolvables.empty?

  evolvable = evolvable_class.new_evolvable(population: self,
                                            genome: genome || search_space.new_genome,
                                            generation_index: @evolvables.count)
  @evolvables << evolvable
  evolvable
end

#new_evolvables(count:, evolvables: nil) ⇒ Object



179
180
181
182
183
184
185
186
187
188
# File 'lib/evolvable/population.rb', line 179

def new_evolvables(count:, evolvables: nil)
  evolvables ||= @evolvables || []
  @evolvables = evolvables

  if parent_evolvables.empty?
    Array.new(count) { new_evolvable(genome: search_space.new_genome) }
  else
    @evolvables = generate_evolvables(count)
  end
end

#new_parent_genome_cycleObject



195
196
197
# File 'lib/evolvable/population.rb', line 195

def new_parent_genome_cycle
  parent_evolvables.map(&:genome).shuffle!.combination(2).cycle
end

#reset_evolvablesObject



190
191
192
193
# File 'lib/evolvable/population.rb', line 190

def reset_evolvables
  self.evolvables = []
  new_evolvables(count: size)
end