Class: Evolvable::Population
- Inherits:
-
Object
- Object
- Evolvable::Population
- Extended by:
- Forwardable
- Defined in:
- lib/evolvable/population.rb
Overview
Populations orchestrate the evolutionary process through four key components:
- Evaluation: Sorts evolvable instances by fitness
- Selection: Chooses parents for combination
- Combination: Creates new evolvables from selected parents
- Mutation: Introduces variation to maintain genetic diversity
Features:
Initialize a population with default or custom parameters:
population = YourEvolvable.new_population(
size: 50,
evaluation: { equalize: 0 },
selection: { size: 10 },
mutation: { probability: 0.2, rate: 0.02 }
)
Or inject fully customized strategy objects:
population = YourEvolvable.new_population(
evaluation: Your::Evaluation.new,
evolution: Your::Evolution.new,
selection: Your::Selection.new,
combination: Your::Combination.new,
mutation: Your::Mutation.new
)
Evolve your population:
population.evolve(count: 20) # Run for 20 generations
population.evolve_to_goal # Run until the current goal is met
population.evolve_to_goal(0.0) # Run until a specific goal is met
population.evolve_forever # Run indefinitely, ignoring any goal
population.evolve_selected([...]) # Use a custom subset of evolvables
Create new evolvables:
new = population.new_evolvable
many = population.new_evolvables(count: 10)
with_genome = population.new_evolvable(genome: another.genome)
Customize the evolution lifecycle by implementing hooks:
def self.before_evaluation(pop); end
def self.before_evolution(pop); end
def self.after_evolution(pop); end
Evaluate progress:
best = population.best_evolvable if population.met_goal?
Constant Summary collapse
- DUMP_METHODS =
List of attributes that can be dumped during serialization.
%i[evolvable_type id name size evolutions_count gene_space evolution evaluation].freeze
Instance Attribute Summary collapse
-
#evaluation ⇒ Evolvable::Evaluation
The evaluation strategy used to assess evolvables.
-
#evolution ⇒ Object
Population properties.
-
#evolutions_count ⇒ Object
Population properties.
-
#evolvable_type ⇒ Object
Population properties.
-
#evolvables ⇒ Object
Population properties.
-
#gene_space ⇒ Object
Population properties.
-
#id ⇒ Object
Population properties.
-
#name ⇒ Object
Population properties.
-
#parent_evolvables ⇒ Object
Population properties.
-
#selected_evolvables ⇒ Object
Population properties.
-
#size ⇒ Object
Population properties.
Class Method Summary collapse
-
.load(data) ⇒ Evolvable::Population
Loads a population from serialized data.
Instance Method Summary collapse
-
#best_evolvable ⇒ Evolvable
Returns the best evolvable in the population according to the evaluation goal.
-
#dump(only: nil, except: nil) ⇒ String
Serializes the population to a string.
-
#dump_attrs(only: nil, except: nil) ⇒ Hash
Returns a hash of attributes for serialization.
-
#evolve(count: 1, goal_value: nil) ⇒ Evolvable::Population
Evolves the population for a specified number of generations or until the goal is achieved.
-
#evolve_forever ⇒ Evolvable::Population
Evolves the population indefinitely, ignoring any goal.
-
#evolve_selected(selected_evolvables) ⇒ Evolvable::Population
Evolves the population using a pre-selected set of evolvables.
-
#evolve_to_goal(goal_value = nil) ⇒ Evolvable::Population
Evolves the population until the goal is met.
-
#initialize(evolvable_type:, id: nil, name: nil, size: 0, evolutions_count: 0, gene_space: nil, parent_evolvables: [], selected_evolvables: [], evaluation: Evaluation.new, evolution: Evolution.new, selection: nil, combination: nil, mutation: nil, evolvables: []) ⇒ Population
constructor
Initializes an Evolvable::Population.
-
#met_goal? ⇒ Boolean
Checks if the goal has been met by any evolvable in the population.
-
#new_evolvable(genome: nil) ⇒ Evolvable
Creates a new evolvable instance with an optional genome.
-
#new_evolvables(count:) ⇒ Array<Evolvable>
Creates multiple new evolvable instances.
-
#new_genome ⇒ Evolvable::Genome
Creates a new genome from the gene space.
-
#new_parent_genome_cycle ⇒ Enumerator
Creates a cycle of parent genome pairs for combination.
-
#reset_evolvables ⇒ Array<Evolvable>
Resets the population by clearing all evolvables and creating new ones.
Constructor Details
#initialize(evolvable_type:, id: nil, name: nil, size: 0, evolutions_count: 0, gene_space: nil, parent_evolvables: [], selected_evolvables: [], evaluation: Evaluation.new, evolution: Evolution.new, selection: nil, combination: nil, mutation: nil, evolvables: []) ⇒ Population
Initializes an Evolvable::Population.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/evolvable/population.rb', line 102 def initialize(evolvable_type:, id: nil, name: nil, size: 0, evolutions_count: 0, gene_space: nil, parent_evolvables: [], selected_evolvables: [], evaluation: Evaluation.new, evolution: Evolution.new, selection: nil, combination: nil, mutation: nil, evolvables: []) @id = id @evolvable_type = evolvable_type.is_a?(Class) ? evolvable_type : Object.const_get(evolvable_type) @name = name @size = size @evolutions_count = evolutions_count @gene_space = initialize_gene_space(gene_space) @parent_evolvables = parent_evolvables @selected_evolvables = selected_evolvables self.evaluation = evaluation @evolution = evolution self.selection = selection if selection self.combination = combination if combination self.mutation = mutation if mutation self.evolvables = evolvables || [] new_evolvables(count: @size - evolvables.count) end |
Instance Attribute Details
#evaluation ⇒ Evolvable::Evaluation
The evaluation strategy used to assess evolvables
184 185 186 |
# File 'lib/evolvable/population.rb', line 184 def evaluation @evaluation end |
#evolution ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def evolution @evolution end |
#evolutions_count ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def evolutions_count @evolutions_count end |
#evolvable_type ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def evolvable_type @evolvable_type end |
#evolvables ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def evolvables @evolvables end |
#gene_space ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def gene_space @gene_space end |
#id ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def id @id end |
#name ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def name @name end |
#parent_evolvables ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def parent_evolvables @parent_evolvables end |
#selected_evolvables ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def selected_evolvables @selected_evolvables end |
#size ⇒ Object
Population properties
136 137 138 |
# File 'lib/evolvable/population.rb', line 136 def size @size end |
Class Method Details
.load(data) ⇒ Evolvable::Population
Loads a population from serialized data.
79 80 81 82 |
# File 'lib/evolvable/population.rb', line 79 def self.load(data) dump_attrs = Serializer.load(data) new(**dump_attrs) end |
Instance Method Details
#best_evolvable ⇒ Evolvable
Returns the best evolvable in the population according to the evaluation goal.
269 270 271 |
# File 'lib/evolvable/population.rb', line 269 def best_evolvable evaluation.best_evolvable(self) end |
#dump(only: nil, except: nil) ⇒ String
Serializes the population to a string.
353 354 355 |
# File 'lib/evolvable/population.rb', line 353 def dump(only: nil, except: nil) Serializer.dump(dump_attrs(only: only, except: except)) end |
#dump_attrs(only: nil, except: nil) ⇒ Hash
Returns a hash of attributes for serialization.
378 379 380 381 382 383 384 |
# File 'lib/evolvable/population.rb', line 378 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 |
#evolve(count: 1, goal_value: nil) ⇒ Evolvable::Population
Evolves the population for a specified number of generations or until the goal is achieved.
210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/evolvable/population.rb', line 210 def evolve(count: 1, 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 |
#evolve_forever ⇒ Evolvable::Population
Evolves the population indefinitely, ignoring any goal.
Clears any previously set goal.value
to ensure evolution continues indefinitely.
244 245 246 247 |
# File 'lib/evolvable/population.rb', line 244 def evolve_forever goal.value = nil evolve(count: Float::INFINITY) end |
#evolve_selected(selected_evolvables) ⇒ Evolvable::Population
Evolves the population using a pre-selected set of evolvables. This allows for custom selection beyond the built-in selection strategies.
256 257 258 259 260 261 262 |
# File 'lib/evolvable/population.rb', line 256 def evolve_selected(selected_evolvables) self.selected_evolvables = selected_evolvables before_evolution(self) evolution.call(self) self.evolutions_count += 1 after_evolution(self) end |
#evolve_to_goal(goal_value = nil) ⇒ Evolvable::Population
Evolves the population until the goal is met.
If no goal value is provided, it uses the currently defined goal.value
.
232 233 234 235 |
# File 'lib/evolvable/population.rb', line 232 def evolve_to_goal(goal_value = nil) goal_value ||= goal.value evolve(count: Float::INFINITY, goal_value: goal_value) end |
#met_goal? ⇒ Boolean
Checks if the goal has been met by any evolvable in the population.
278 279 280 |
# File 'lib/evolvable/population.rb', line 278 def met_goal? evaluation.met_goal?(self) end |
#new_evolvable(genome: nil) ⇒ Evolvable
Creates a new evolvable instance with an optional genome. If no genome is provided and there are parent evolvables, a genome will be generated through combination.
290 291 292 293 294 295 296 297 298 |
# File 'lib/evolvable/population.rb', line 290 def new_evolvable(genome: nil) return generate_evolvables(1).first unless genome || parent_evolvables.empty? evolvable = evolvable_type.new_evolvable(population: self, genome: genome || new_genome, generation_index: @evolvables.count) @evolvables << evolvable evolvable end |
#new_evolvables(count:) ⇒ Array<Evolvable>
Creates multiple new evolvable instances.
306 307 308 309 310 311 312 313 314 315 |
# File 'lib/evolvable/population.rb', line 306 def new_evolvables(count:) if parent_evolvables.empty? Array.new(count) { new_evolvable(genome: new_genome) } else evolvables = generate_evolvables(count) @evolvables ||= [] @evolvables.concat evolvables evolvables end end |
#new_genome ⇒ Evolvable::Genome
Creates a new genome from the gene space.
322 323 324 |
# File 'lib/evolvable/population.rb', line 322 def new_genome gene_space.new_genome end |
#new_parent_genome_cycle ⇒ Enumerator
Creates a cycle of parent genome pairs for combination. Shuffles parent genomes and creates combinations of two.
342 343 344 |
# File 'lib/evolvable/population.rb', line 342 def new_parent_genome_cycle parent_evolvables.map(&:genome).shuffle!.combination(2).cycle end |
#reset_evolvables ⇒ Array<Evolvable>
Resets the population by clearing all evolvables and creating new ones.
331 332 333 334 |
# File 'lib/evolvable/population.rb', line 331 def reset_evolvables self.evolvables = [] new_evolvables(count: size) end |