Class: Darwinning::Population
- Inherits:
-
Object
- Object
- Darwinning::Population
- Defined in:
- lib/darwinning/population.rb
Constant Summary collapse
- DEFAULT_EVOLUTION_TYPES =
[ Darwinning::EvolutionTypes::Reproduction.new, Darwinning::EvolutionTypes::Mutation.new(mutation_rate: 0.10) ]
Instance Attribute Summary collapse
-
#evolution_types ⇒ Object
Returns the value of attribute evolution_types.
-
#fitness_goal ⇒ Object
Returns the value of attribute fitness_goal.
-
#generation ⇒ Object
Returns the value of attribute generation.
-
#generations_limit ⇒ Object
Returns the value of attribute generations_limit.
-
#members ⇒ Object
Returns the value of attribute members.
-
#organism ⇒ Object
Returns the value of attribute organism.
-
#population_size ⇒ Object
Returns the value of attribute population_size.
Instance Method Summary collapse
- #apply_non_pairwise_evolutions(members) ⇒ Object
- #apply_pairwise_evolutions(organism, m1, m2) ⇒ Object
- #best_member ⇒ Object
- #build_population(population_size) ⇒ Object
- #evolution_over? ⇒ Boolean
- #evolve! ⇒ Object
-
#initialize(options = {}) ⇒ Population
constructor
A new instance of Population.
- #make_next_generation! ⇒ Object
- #set_members_fitness!(fitness_values) ⇒ Object
- #size ⇒ Object
- #weighted_select(members) ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ Population
Returns a new instance of Population.
13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/darwinning/population.rb', line 13 def initialize( = {}) @organism = .fetch(:organism) @population_size = .fetch(:population_size) @fitness_goal = .fetch(:fitness_goal) @generations_limit = .fetch(:generations_limit, 0) @evolution_types = .fetch(:evolution_types, DEFAULT_EVOLUTION_TYPES) @members = [] @generation = 0 # initial population is generation 0 build_population(@population_size) end |
Instance Attribute Details
#evolution_types ⇒ Object
Returns the value of attribute evolution_types.
6 7 8 |
# File 'lib/darwinning/population.rb', line 6 def evolution_types @evolution_types end |
#fitness_goal ⇒ Object
Returns the value of attribute fitness_goal.
4 5 6 |
# File 'lib/darwinning/population.rb', line 4 def fitness_goal @fitness_goal end |
#generation ⇒ Object
Returns the value of attribute generation.
5 6 7 |
# File 'lib/darwinning/population.rb', line 5 def generation @generation end |
#generations_limit ⇒ Object
Returns the value of attribute generations_limit.
4 5 6 |
# File 'lib/darwinning/population.rb', line 4 def generations_limit @generations_limit end |
#members ⇒ Object
Returns the value of attribute members.
4 5 6 |
# File 'lib/darwinning/population.rb', line 4 def members @members end |
#organism ⇒ Object
Returns the value of attribute organism.
5 6 7 |
# File 'lib/darwinning/population.rb', line 5 def organism @organism end |
#population_size ⇒ Object
Returns the value of attribute population_size.
5 6 7 |
# File 'lib/darwinning/population.rb', line 5 def population_size @population_size end |
Instance Method Details
#apply_non_pairwise_evolutions(members) ⇒ Object
94 95 96 97 98 99 100 101 102 |
# File 'lib/darwinning/population.rb', line 94 def apply_non_pairwise_evolutions(members) evolution_types.inject(members) do |ret, evolution_type| if evolution_type.pairwise? ret else evolution_type.evolve(ret) end end end |
#apply_pairwise_evolutions(organism, m1, m2) ⇒ Object
84 85 86 87 88 89 90 91 92 |
# File 'lib/darwinning/population.rb', line 84 def apply_pairwise_evolutions(organism, m1, m2) evolution_types.inject([m1, m2]) do |ret, evolution_type| if evolution_type.pairwise? evolution_type.evolve(organism, *ret) else ret end end end |
#best_member ⇒ Object
113 114 115 |
# File 'lib/darwinning/population.rb', line 113 def best_member @members.sort_by { |m| m.fitness }.first end |
#build_population(population_size) ⇒ Object
25 26 27 28 29 |
# File 'lib/darwinning/population.rb', line 25 def build_population(population_size) population_size.times do |i| @members << organism.new end end |
#evolution_over? ⇒ Boolean
104 105 106 107 108 109 110 111 |
# File 'lib/darwinning/population.rb', line 104 def evolution_over? # check if the fiteness goal or generation limit has been met if generations_limit > 0 generation == generations_limit || best_member.fitness == fitness_goal else generation == generations_limit || best_member.fitness == fitness_goal end end |
#evolve! ⇒ Object
31 32 33 34 35 |
# File 'lib/darwinning/population.rb', line 31 def evolve! until evolution_over? make_next_generation! end end |
#make_next_generation! ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/darwinning/population.rb', line 65 def make_next_generation! temp_members = members used_members = [] new_members = [] until new_members.length == members.length / 2 m1 = weighted_select(members - used_members) used_members << m1 m2 = weighted_select(members - used_members) used_members << m2 new_members << apply_pairwise_evolutions(organism, m1, m2) end new_members.flatten! @members = apply_non_pairwise_evolutions(new_members) @generation += 1 end |
#set_members_fitness!(fitness_values) ⇒ Object
61 62 63 |
# File 'lib/darwinning/population.rb', line 61 def set_members_fitness!(fitness_values) members.to_enum.each_with_index { |m, i| m.fitness = fitness_values[i] } end |
#size ⇒ Object
117 118 119 |
# File 'lib/darwinning/population.rb', line 117 def size @members.length end |
#weighted_select(members) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/darwinning/population.rb', line 37 def weighted_select(members) e = 0.01 fitness_sum = members.inject(0) { |sum, m| sum + m.fitness } weighted_members = members.sort_by do |m| (m.fitness - fitness_goal).abs end.map do |m| [m, fitness_sum / ((m.fitness - fitness_goal).abs + e)] end weight_sum = weighted_members.inject(0) { |sum, m| sum + m[1] } pick = (0..weight_sum).to_a.sample weighted_members.reverse! # In order to pop from the end we need the lowest ranked first pick_sum = 0 until pick_sum > pick do selected_member = weighted_members.pop pick_sum += selected_member[1] end selected_member.first end |