Class: Darwinning::Population

Inherits:
Object
  • Object
show all
Defined in:
lib/darwinning/population.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(organism, population_size, fitness_goal, mutation_rate = 0.0, generations_limit = 0, manual_fitness = false) ⇒ Population

Returns a new instance of Population.



6
7
8
9
10
11
12
13
14
15
16
# File 'lib/darwinning/population.rb', line 6

def initialize(organism, population_size, fitness_goal, mutation_rate = 0.0, generations_limit = 0, manual_fitness = false)
  @organism = organism
  @fitness_goal = fitness_goal
  @mutation_rate = mutation_rate
  @generations_limit = generations_limit
  @manual_fitness = manual_fitness
  @members = []
  @generation = 0 # initial population is generation 0

  build_population(population_size)
end

Instance Attribute Details

#fitness_goalObject

Returns the value of attribute fitness_goal.



4
5
6
# File 'lib/darwinning/population.rb', line 4

def fitness_goal
  @fitness_goal
end

#generationObject

Returns the value of attribute generation.



4
5
6
# File 'lib/darwinning/population.rb', line 4

def generation
  @generation
end

#generations_limitObject

Returns the value of attribute generations_limit.



4
5
6
# File 'lib/darwinning/population.rb', line 4

def generations_limit
  @generations_limit
end

#membersObject

Returns the value of attribute members.



4
5
6
# File 'lib/darwinning/population.rb', line 4

def members
  @members
end

#mutation_rateObject

Returns the value of attribute mutation_rate.



4
5
6
# File 'lib/darwinning/population.rb', line 4

def mutation_rate
  @mutation_rate
end

#organismObject

Returns the value of attribute organism.



4
5
6
# File 'lib/darwinning/population.rb', line 4

def organism
  @organism
end

Instance Method Details

#best_memberObject



112
113
114
# File 'lib/darwinning/population.rb', line 112

def best_member
  @members.sort_by { |m| m.fitness }[0]
end

#build_population(population_size) ⇒ Object



18
19
20
21
22
# File 'lib/darwinning/population.rb', line 18

def build_population(population_size)
  population_size.times do |i|
    @members << @organism.new
  end
end

#crossover(m1, m2) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/darwinning/population.rb', line 30

def crossover(m1, m2)
  genotypes1 = []
  genotypes2 = []

  m1.genotypes.zip(m2.genotypes).each do |g|
    if m1.genotypes.index(g[0]) % 2 == 0
      genotypes1 << g[0]
      genotypes2 << g[1]
    else
      genotypes1 << g[1]
      genotypes2 << g[0]
    end
  end

  [@organism.new(genotypes1), @organism.new(genotypes2)]
end

#evolution_over?Boolean

Returns:

  • (Boolean)


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

def evolution_over?
  # check if the fiteness goal or generation limit has been met
  @generation == @generations_limit or best_member.fitness == @fitness_goal
end

#evolve!Object



24
25
26
27
28
# File 'lib/darwinning/population.rb', line 24

def evolve!
  until evolution_over?
    make_next_generation!
  end
end

#make_next_generation!Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/darwinning/population.rb', line 85

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 << crossover(m1,m2)
  end

  new_members.flatten!

  @members = new_members

  mutate!
  @generation += 1
end

#mutate!Object



71
72
73
74
75
76
77
78
79
# File 'lib/darwinning/population.rb', line 71

def mutate!
  @members.map! { |m|
    if (0..100).to_a.sample < @mutation_rate*100
      m.mutate!
    else
      m
    end
  }
end

#set_members_fitness!(fitness_values) ⇒ Object



81
82
83
# File 'lib/darwinning/population.rb', line 81

def set_members_fitness!(fitness_values)
  @members.to_enum.each_with_index { |m, i| m.fitness = fitness_values[i] }
end

#sexytimes(m1, m2) ⇒ Object



47
48
49
# File 'lib/darwinning/population.rb', line 47

def sexytimes(m1, m2)
  crossover(m1, m2)
end

#sizeObject



116
117
118
# File 'lib/darwinning/population.rb', line 116

def size
  @members.length
end

#weighted_select(members) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/darwinning/population.rb', line 51

def weighted_select(members)
  e = 0.01
  fitness_sum = members.inject(0) { |sum, m| sum + m.fitness }

  weighted_members = members.sort_by { |m| (m.fitness - @fitness_goal).abs }.map { |m| [m, fitness_sum / ((m.fitness - @fitness_goal).abs + e)] }

  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[0]
end