gemetics 0.0.3 → 0.1.0
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.
- checksums.yaml +4 -4
- data/lib/gemetics.rb +112 -43
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03348853673a345fd2653bf0300963de087664ef
|
4
|
+
data.tar.gz: e0bc73e5ed66e085a859769b7ac2f644eacae404
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d593ebf10f86fe18f6fade87886b39834bdd01cf10f581cf8528e262c4fa2caf92e1d155bfc744af4a647b3f62d7e56dd450240eac3c49d41594070b503e3cb4
|
7
|
+
data.tar.gz: b4191a88f4cf2163ad10033b1afed03e573946ba42419a63053a88505ec9e8a0fa52b4072f1db0ec498f4ae4997d2a6271cfd7cf7d4d4deaf0d03c19aa512c38
|
data/lib/gemetics.rb
CHANGED
@@ -9,55 +9,64 @@ def default_GA_options()
|
|
9
9
|
mutationPercent: 0.05,
|
10
10
|
elitism: 0,
|
11
11
|
debug: false,
|
12
|
+
tournamentSize: 10,
|
12
13
|
}
|
13
14
|
end
|
14
15
|
|
15
16
|
def runGeneticAlgorithm(initialPopulation, eval, threshold, options)
|
16
|
-
|
17
|
+
# make sure options is assigned
|
17
18
|
if(options == nil)
|
18
|
-
options = default_GA_options
|
19
|
+
options = default_GA_options()
|
19
20
|
end
|
20
|
-
validOptions(options,
|
21
|
+
validOptions(options,initialPopulation.size()) # Raises error if options are not correct
|
21
22
|
currentGen = 0
|
22
23
|
bestCanidate = initialPopulation[0]
|
23
24
|
population = initialPopulation
|
24
25
|
while(continue?(bestCanidate.fitness, threshold, currentGen, options)) do
|
25
|
-
if(options[:debug])
|
26
|
-
puts 'Best Canidate Soultion:'
|
27
|
-
puts bestCanidate.inspect
|
28
|
-
puts 'Current Generation:'
|
29
|
-
puts currentGen
|
30
|
-
end
|
31
26
|
# evaluate the population
|
32
27
|
population = eval.call(population)
|
33
|
-
|
28
|
+
|
29
|
+
if(options[:greaterBetter])
|
34
30
|
sortedPopulation = population.sort{ |x , y| y.fitness <=> x.fitness }
|
35
31
|
else
|
36
32
|
sortedPopulation = population.sort{ |x , y| x.fitness <=> y.fitness }
|
37
33
|
end
|
38
34
|
bestCanidate = population[0].clone
|
39
35
|
|
36
|
+
if(options[:debug])
|
37
|
+
puts 'Best Canidate Soultion:'
|
38
|
+
puts bestCanidate.inspect
|
39
|
+
puts 'Current Generation:'
|
40
|
+
puts currentGen
|
41
|
+
puts 'Average Fitness:'
|
42
|
+
cumulative = 0
|
43
|
+
for org in population
|
44
|
+
cumulative += org.fitness
|
45
|
+
end
|
46
|
+
puts cumulative/population.size()
|
47
|
+
end
|
48
|
+
|
40
49
|
|
41
50
|
if(options[:totalPopReplace] == false)
|
42
51
|
# Do not replace every organism
|
43
|
-
mates = selection(sortedPopulation.clone(), options
|
52
|
+
mates = selection(sortedPopulation.clone(), options)
|
44
53
|
|
45
54
|
# mate and replace
|
46
55
|
results = mateOrgs(mates[0], mates[1])
|
47
56
|
replaced = []
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
57
|
+
if(options[:elitism] > 0)
|
58
|
+
population = sortedPopulation
|
59
|
+
for i in 0...options[:elitism]
|
60
|
+
replaced.append(i)
|
61
|
+
end
|
62
|
+
end
|
54
63
|
for i in 0...results.size()
|
55
64
|
results[i].mutate() if Random.new.rand() < options[:mutationPercent]
|
56
65
|
temp = Random.new.rand(population.size())
|
57
|
-
while(
|
66
|
+
while(replaced.include?(temp)) do
|
58
67
|
temp = Random.new.rand(population.size())
|
59
68
|
end
|
60
|
-
replaced.
|
69
|
+
replaced.push(temp)
|
61
70
|
population[replaced[-1]] = results[i]
|
62
71
|
end
|
63
72
|
else
|
@@ -65,24 +74,19 @@ def runGeneticAlgorithm(initialPopulation, eval, threshold, options)
|
|
65
74
|
needed = population.size()
|
66
75
|
have = 0
|
67
76
|
newPopulation = Array.new(population.size(), GeneticObject.new)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
for i in 0...options[:elitism]
|
75
|
-
newPopulation[i] = sortedPopulation[i]
|
76
|
-
end
|
77
|
-
end
|
77
|
+
if(options[:elitism] > 0)
|
78
|
+
for i in 0...options[:elitism]
|
79
|
+
newPopulation[i] = sortedPopulation[i]
|
80
|
+
end
|
81
|
+
end
|
78
82
|
while have < needed do
|
79
|
-
mates = selection(sortedPopulation.clone(), options
|
83
|
+
mates = selection(sortedPopulation.clone(), options)
|
80
84
|
|
81
85
|
# mate and put them into new pop
|
82
86
|
results = mateOrgs(mates[0], mates[1])
|
83
87
|
for i in 0...results.size()
|
84
88
|
results[i].mutate() if Random.new.rand() < options[:mutationPercent]
|
85
|
-
newPopulation[have+i] =
|
89
|
+
newPopulation[have+i] = results[i] if (have+i) < needed
|
86
90
|
end
|
87
91
|
have += results.size()
|
88
92
|
end
|
@@ -98,13 +102,13 @@ end
|
|
98
102
|
|
99
103
|
def continue?(highestFitness, threshold, currentGen, options)
|
100
104
|
return false if exceedsThreshold?(options[:greaterBetter], highestFitness, threshold)
|
101
|
-
return false if currentGen > options[:
|
105
|
+
return false if currentGen > options[:genMax]
|
102
106
|
return true
|
103
107
|
end
|
104
108
|
|
105
109
|
def exceedsThreshold?(greaterBetter, val, threshold)
|
106
110
|
if(val == nil)
|
107
|
-
|
111
|
+
return false
|
108
112
|
end
|
109
113
|
if(greaterBetter)
|
110
114
|
return val>=threshold
|
@@ -114,25 +118,73 @@ def exceedsThreshold?(greaterBetter, val, threshold)
|
|
114
118
|
return false
|
115
119
|
end
|
116
120
|
|
117
|
-
def selection(population,
|
121
|
+
def selection(population, options)
|
118
122
|
# select mates
|
119
|
-
if(
|
120
|
-
return tournamentSelection(population)
|
121
|
-
elsif(
|
123
|
+
if(options[:selectionStyle] == 'tournament')
|
124
|
+
return tournamentSelection(population, options[:tournamentSize])
|
125
|
+
elsif(options[:selectionStyle] == 'best')
|
122
126
|
return bestSelection(population)
|
127
|
+
elsif(options[:selectionStyle] == 'roulette')
|
128
|
+
return rouletteSelection(population)
|
123
129
|
end
|
124
130
|
raise 'Problem with selection type'
|
125
131
|
end
|
126
132
|
|
127
|
-
|
133
|
+
# Selection algorithms are based on population being sorted
|
134
|
+
|
135
|
+
def tournamentSelection(population, size)
|
128
136
|
population = population.shuffle
|
129
|
-
|
137
|
+
subPop = population[0...size]
|
138
|
+
additiveFitness = 0
|
139
|
+
result = []
|
140
|
+
for member in subPop
|
141
|
+
additiveFitness += member.fitness
|
142
|
+
end
|
143
|
+
for member in subPop
|
144
|
+
if Random.new.rand() <= (member.fitness/additiveFitness)
|
145
|
+
result.push(member)
|
146
|
+
break
|
147
|
+
end
|
148
|
+
end
|
149
|
+
for member in subPop
|
150
|
+
if Random.new.rand() <= (member.fitness/additiveFitness)
|
151
|
+
result.push(member)
|
152
|
+
break
|
153
|
+
end
|
154
|
+
end
|
155
|
+
result.push(subPop[0]) while result.size() < 2
|
156
|
+
return result
|
130
157
|
end
|
131
158
|
|
132
159
|
def bestSelection(population)
|
133
160
|
return population[0..1]
|
134
161
|
end
|
135
162
|
|
163
|
+
def rouletteSelection(population)
|
164
|
+
additiveFitness = 0.0
|
165
|
+
for member in population
|
166
|
+
additiveFitness += member.fitness
|
167
|
+
end
|
168
|
+
|
169
|
+
result = []
|
170
|
+
for member in population
|
171
|
+
if Random.new.rand() <= (member.fitness/additiveFitness)
|
172
|
+
result.push(member)
|
173
|
+
break
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
for member in population
|
178
|
+
if Random.new.rand() <= (member.fitness/additiveFitness)
|
179
|
+
result.push(member)
|
180
|
+
break
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
result.push(population[0]) while result.size() < 2
|
185
|
+
return result
|
186
|
+
end
|
187
|
+
|
136
188
|
def mateOrgs(one, two)
|
137
189
|
return one.mate(two)
|
138
190
|
end
|
@@ -141,17 +193,27 @@ end
|
|
141
193
|
|
142
194
|
def validOptions(options, populationSize)
|
143
195
|
raise 'Required Option Missing' if !hasRequiredOptions(options)
|
196
|
+
raise 'Required Dependent Options Missing' if !hasRequiredDependentOptions(options)
|
144
197
|
raise 'Options Not Within Limits' if !withinLimits(options, populationSize)
|
198
|
+
raise 'Dependent Options Not Within Limits' if !dependentOptionsWithinLimits(options, populationSize)
|
145
199
|
return true
|
146
200
|
end
|
147
201
|
|
148
202
|
def hasRequiredOptions(options)
|
149
203
|
return false if !options.has_key?(:greaterBetter)
|
150
204
|
return false if !options.has_key?(:totalPopReplace)
|
205
|
+
return false if !options.has_key?(:selectionStyle)
|
151
206
|
return false if !options.has_key?(:genMax)
|
152
|
-
return false if !options.has_key?(:
|
207
|
+
return false if !options.has_key?(:mutationPercent)
|
153
208
|
return false if !options.has_key?(:debug)
|
154
|
-
|
209
|
+
return false if !options.has_key?(:elitism)
|
210
|
+
return true
|
211
|
+
end
|
212
|
+
|
213
|
+
def hasRequiredDependentOptions(options)
|
214
|
+
if(options[:selectionStyle] == 'tournament')
|
215
|
+
return false if !options.has_key?(:tournamentSize)
|
216
|
+
end
|
155
217
|
return true
|
156
218
|
end
|
157
219
|
|
@@ -159,13 +221,20 @@ def withinLimits(options, populationSize)
|
|
159
221
|
possibleGreaterBetter = [true, false]
|
160
222
|
possibleTotalPopReplace = [true, false]
|
161
223
|
possibleDebug = [true, false]
|
162
|
-
possibleSelectionStyle = ['tournament', 'best']
|
224
|
+
possibleSelectionStyle = ['tournament', 'best', 'roulette']
|
163
225
|
return false if !(possibleGreaterBetter.include?(options[:greaterBetter]))
|
164
226
|
return false if !(possibleTotalPopReplace.include?(options[:totalPopReplace]))
|
165
227
|
return false if !(options[:genMax]>0)
|
166
228
|
return false if !(possibleSelectionStyle.include?(options[:selectionStyle]))
|
167
229
|
return false if !(options[:mutationPercent]>0.0)
|
168
230
|
return false if !(possibleDebug.include?(options[:debug]))
|
169
|
-
|
231
|
+
return false if !(options[:elitism]>=0 && options[:elitism]<populationSize)
|
232
|
+
return true
|
233
|
+
end
|
234
|
+
|
235
|
+
def dependentOptionsWithinLimits(options, populationSize)
|
236
|
+
if(options[:selectionStyle] == 'tournament')
|
237
|
+
return false if !(options[:tournamentSize] > 0 && options[:tournamentSize] <= populationSize)
|
238
|
+
end
|
170
239
|
return true
|
171
240
|
end
|