genetic_framework 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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