genetic_framework 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/genetic_framework.rb +46 -25
  2. metadata +3 -3
@@ -1,13 +1,15 @@
1
1
  class Array
2
-
3
2
  def random_element
4
3
  self[Random.rand(self.size)]
5
4
  end
6
5
  end
7
6
 
7
+ #represents a pool of evolving strings towards a solution
8
8
  class GenePool
9
+
10
+ #represents a single potential solution to the problem - contains
11
+ #the string encoding and the fitness of that encoding.
9
12
  class Spawn
10
-
11
13
  attr_reader :string, :fitness
12
14
 
13
15
  def initialize(fitness, string)
@@ -18,9 +20,20 @@ class GenePool
18
20
  def <=>(other)
19
21
  return self.fitness <=> other.fitness
20
22
  end
21
-
22
- end
23
+ end#end class Spawn
23
24
 
25
+ #gen_size is the number of spawn per generation, should be even
26
+ #encoding_map is a list of lists, where each position in the
27
+ #containing list is the equivalent position in the string encoding,
28
+ #and the list at that position contains all possible characters allowed
29
+ #at that position.
30
+ #TODO might not be wise to couple GenePool to the generation initialization.
31
+ #mutation_prob is the probability of mutation at each character of the encoding
32
+ #cull_threshold, if provided, is the minimum fitness score allowed to reproduce.
33
+ # will not activate until enough sufficiently fit spawn are created
34
+ #elite, if provided, saves that number of the highest scoring spawn and passes
35
+ # them directly into the next generation. Should be even.
36
+ #fitness is the function that evaluates a string (in this case, I try to maximize fitness)
24
37
  def initialize(gen_size, encoding_map, mutation_prob, cull_threshold = nil, elite = 0, initial_gen = nil, &fitness)
25
38
  @gen_size = gen_size
26
39
  @encoding_map = encoding_map
@@ -31,7 +44,7 @@ class GenePool
31
44
  if !initial_gen
32
45
  @gen = initialize_gen.map {|str| Spawn.new(yield(str), str)}
33
46
  end
34
- end
47
+ end#end initialize
35
48
 
36
49
  attr_accessor :gen_size, :cull_threshold, :mutation_prob, :elite
37
50
  attr_reader :gen, :encoding_map
@@ -46,24 +59,27 @@ class GenePool
46
59
  spawn << position.random_element
47
60
  end
48
61
  return spawn.join
49
- end
62
+ end#end build_spawn
50
63
 
51
64
  #char_map should be an array with length identical to string encoding length
52
65
  #and each position contains a list of chars possible for that position
66
+ #creates and returns an initial generation of @gen_size according
67
+ #to @encoding_map
53
68
  def initialize_gen
54
69
  pop = []
55
70
  1.upto(@gen_size) do |spawn_num|
56
71
  pop << build_spawn
57
72
  end
58
73
  return pop
59
- end
74
+ end#end initialize_gen
60
75
 
61
-
62
- def random_sexual_selection
76
+ #finds and returns the "parent" solutions who will "mate".
77
+ #takes a number of parents to select
78
+ def random_sexual_selection(num_parents)
63
79
  selected = []
64
80
  candidates = []
65
81
 
66
- #create a list of candidates who meet the requirements (all if there is no cull)
82
+ #create a list of candidates who meet the requirements (all if there is no cull or not enough fit spawn)
67
83
  #a candidate shows up in the list once for each fitness level. This may be memory heavy,
68
84
  #so TODO improve the selection based on fitness
69
85
  strong = @gen.select {|spawn| !@cull_threshold or spawn.fitness >= @cull_threshold}
@@ -80,11 +96,11 @@ class GenePool
80
96
 
81
97
  #select from amount candidates a generation_size number of parents. Candidates can be selected
82
98
  #more than once, and have a higher chance of being selected for a higher fitness score
83
- 1.upto(@gen_size) do
99
+ 1.upto(num_parents) do
84
100
  selected << candidates.random_element
85
101
  end
86
102
  return selected
87
- end
103
+ end#end random_sexual_selection
88
104
 
89
105
  #mates two parent strings to create two child strings
90
106
  def sexually_reproduce(parent1, parent2)
@@ -92,8 +108,11 @@ class GenePool
92
108
  child1 = parent1[0, crossover] + parent2[crossover, parent2.size]
93
109
  child2 = parent2[0, crossover] + parent1[crossover, parent2.size]
94
110
  return [child1, child2]
95
- end
111
+ end#end sexually_reproduce
96
112
 
113
+ #traverses the string and with probability @mutation_prob randomly
114
+ #reassigns one of the characters to a different character in the
115
+ #map for that position
97
116
  def mutate(string)
98
117
  0.upto(string.size - 1) do |str_index|
99
118
  if Random.rand < @mutation_prob
@@ -101,35 +120,37 @@ class GenePool
101
120
  end
102
121
  end
103
122
  return string
104
- end
123
+ end#end mutate
105
124
 
106
125
  public
107
126
 
108
- #takes generation and evolves it one generation. if generation is nil, returns an initial, random generation
109
- #the char_map is a list of lists - each position has a list of chars that are valid for that position.
127
+ #evolves the current pool one generation. if generation is nil, returns an initial, random generation
110
128
  #it tells us both how long each string is and what sort of encodings are valid for creation.
111
129
  #Resulting generation is sorted according to fitness from least to greatest.
112
130
  def evolve
113
131
  #select spawn who will breed
114
- parents = random_sexual_selection
132
+
115
133
  #generation size should be even... or the last parent selected will be ignored
116
134
  #breed new spawn
117
135
  new_gen = []
118
-
119
136
  if @elite
120
137
  1.upto(@elite) do |offset|
121
- if offset > @gen.size then break end
138
+ break if offset > @gen.size
122
139
  new_gen << @gen[-offset]
123
140
  end
124
- end
125
- start_count = new_gen.size
126
- (start_count..@gen_size - 1).step(2) do |index|
141
+ end#end elite selection
142
+
143
+ parents = random_sexual_selection(@gen_size - new_gen.size)
144
+
145
+ #fill remaining slots with bred children
146
+
147
+ (0..parents.size - 1).step(2) do |index|
127
148
  new_gen += sexually_reproduce(parents[index].string, parents[index + 1].string).map do |child_string|
128
149
  s = mutate(child_string)
129
150
  Spawn.new(@fitness.call(s), s)
130
151
  end
131
- end
152
+ end#end create children
132
153
 
133
154
  @gen = new_gen.sort
134
- end
135
- end
155
+ end#end evolve
156
+ end#end class GenePool
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 4
9
- version: 0.0.4
8
+ - 5
9
+ version: 0.0.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Fults
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-03-06 00:00:00 -05:00
17
+ date: 2012-04-17 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies: []
20
20