feldtruby 0.3.16 → 0.3.18
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 +7 -0
- data/Gemfile.lock +9 -2
- data/Rakefile +8 -0
- data/feldtruby.gemspec +6 -0
- data/lib/feldtruby/annotations.rb +10 -0
- data/lib/feldtruby/array/basic_stats.rb +3 -1
- data/lib/feldtruby/array/permutations_and_subsets.rb +17 -0
- data/lib/feldtruby/float.rb +23 -0
- data/lib/feldtruby/logger.rb +216 -30
- data/lib/feldtruby/minitest_extensions.rb +0 -1
- data/lib/feldtruby/mongodb.rb +16 -0
- data/lib/feldtruby/mongodb_logger.rb +245 -0
- data/lib/feldtruby/optimize/differential_evolution.rb +29 -5
- data/lib/feldtruby/optimize/elite_archive.rb +91 -0
- data/lib/feldtruby/optimize/max_steps_termination_criterion.rb +1 -1
- data/lib/feldtruby/optimize/objective.rb +343 -222
- data/lib/feldtruby/optimize/optimizer.rb +138 -60
- data/lib/feldtruby/optimize/search_space.rb +10 -0
- data/lib/feldtruby/optimize.rb +1 -26
- data/lib/feldtruby/statistics.rb +74 -3
- data/lib/feldtruby/time.rb +19 -0
- data/lib/feldtruby/version.rb +1 -1
- data/old/event_logger.rb +682 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/analyze_sampler_comparison_results.R +78 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/compare_samplers.rb +264 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_130405_175934.csv +561 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder.csv +11201 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder_all_radii_4_to_30.csv +44801 -0
- data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_omnitest.csv +1401 -0
- data/spikes/mongodb_logger.rb +47 -0
- data/spikes/simple_de_run.rb +32 -0
- data/test/helper.rb +17 -1
- data/test/test_array_basic_stats.rb +5 -1
- data/test/test_array_permutations_and_subsets.rb +23 -0
- data/test/test_float.rb +15 -0
- data/test/test_html_doc_getter.rb +1 -1
- data/test/test_logger.rb +86 -48
- data/test/test_mongodb_logger.rb +116 -0
- data/test/test_object_annotations.rb +14 -0
- data/test/test_optimize.rb +7 -6
- data/test/test_optimize_differential_evolution.rb +21 -19
- data/test/test_optimize_elite_archive.rb +85 -0
- data/test/test_optimize_objective.rb +237 -74
- data/test/test_optimize_populationbasedoptimizer.rb +72 -6
- data/test/test_optimize_random_search.rb +0 -17
- data/test/test_optimize_search_space.rb +15 -0
- data/test/test_statistics.rb +30 -4
- data/test/test_time.rb +22 -0
- data/test/tmp_shorter.csv +200 -0
- metadata +62 -21
@@ -0,0 +1,78 @@
|
|
1
|
+
#data <- read.csv("/Users/feldt/dev/feldtruby/spikes/results_comparing_samplers_levi13_beale_easom_eggholder.csv")
|
2
|
+
|
3
|
+
source("/Users/feldt/feldt/general/web/advice/statistics/nonparametric_effect_sizes.r")
|
4
|
+
|
5
|
+
data <- read.csv("/Users/feldt/dev/feldtruby/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder_all_radii_4_to_30.csv")
|
6
|
+
#data <- read.csv("/Users/feldt/dev/feldtruby/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_omnitest.csv")
|
7
|
+
data2 <- read.csv("/Users/feldt/dev/feldtruby/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_130405_175934.csv")
|
8
|
+
|
9
|
+
# Combine Sampler and Radius into one column and use shorter name for Sampler.
|
10
|
+
data$SamplerRadius <- sapply(data, function(x) paste(ifelse(data$Sampler=="PopulationSampler", "PS", "RL"), data$Radius, sep=""))[,1]
|
11
|
+
data2$SamplerRadius <- sapply(data2, function(x) paste(ifelse(data2$Sampler=="PopulationSampler", "PS", "RL"), data2$Radius, sep=""))[,1]
|
12
|
+
|
13
|
+
# Select only columns we need
|
14
|
+
d <- subset(data, select = c(Problem, SamplerRadius, Q, NumSteps))
|
15
|
+
d2 <- subset(data2, select = c(Problem, SamplerRadius, Q, NumSteps))
|
16
|
+
|
17
|
+
print_mean_per_sampler <- function(d, numsteps) {
|
18
|
+
for(p in levels(unique(d$Problem))) {
|
19
|
+
ds <- subset(d, Problem == p & NumSteps == numsteps)
|
20
|
+
|
21
|
+
cat("Problem = ", p, "\n");
|
22
|
+
print(aggregate(. ~ SamplerRadius, ds, mean));
|
23
|
+
cat("\n");
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
library(ggplot2)
|
28
|
+
|
29
|
+
pwt <- function(data, problem, numsteps) {
|
30
|
+
d <- subset(data, Problem == problem & NumSteps == numsteps)
|
31
|
+
d$SamplerRadius <- with(d, reorder(SamplerRadius, Q, median))
|
32
|
+
with(d, pairwise.wilcox.test(Q, SamplerRadius))
|
33
|
+
}
|
34
|
+
|
35
|
+
boxplot_numsteps_problem <- function(data, problem, numsteps) {
|
36
|
+
d <- subset(data, Problem == problem & NumSteps == numsteps)
|
37
|
+
d$SamplerRadius <- with(d, reorder(SamplerRadius, Q, median))
|
38
|
+
print(pwt(data, problem, numsteps))
|
39
|
+
p <- ggplot(d, aes(SamplerRadius, Q))
|
40
|
+
p + geom_boxplot()
|
41
|
+
}
|
42
|
+
|
43
|
+
effect.size <- function(data, problem, numsteps, sr1, sr2) {
|
44
|
+
d <- subset(data, Problem == problem & NumSteps == numsteps)
|
45
|
+
d$SamplerRadius <- with(d, reorder(SamplerRadius, Q, median))
|
46
|
+
d1 <- subset(d, SamplerRadius == sr1)
|
47
|
+
d2 <- subset(d, SamplerRadius == sr2)
|
48
|
+
a.statistic(d1$Q, d2$Q)
|
49
|
+
}
|
50
|
+
|
51
|
+
boxplot_numsteps_problem(d, "MinLeviFunctionNum13", 1000)
|
52
|
+
boxplot_numsteps_problem(d, "MinLeviFunctionNum13", 5000)
|
53
|
+
boxplot_numsteps_problem(d, "MinLeviFunctionNum13", 10000)
|
54
|
+
boxplot_numsteps_problem(d, "MinLeviFunctionNum13", 25000)
|
55
|
+
boxplot_numsteps_problem(d, "MinLeviFunctionNum13", 50000)
|
56
|
+
print_mean_per_sampler(d, 10000)
|
57
|
+
|
58
|
+
boxplot_numsteps_problem(d, "MinBealeFunction", 1000)
|
59
|
+
boxplot_numsteps_problem(d, "MinBealeFunction", 5000)
|
60
|
+
boxplot_numsteps_problem(d, "MinBealeFunction", 10000)
|
61
|
+
boxplot_numsteps_problem(d, "MinBealeFunction", 25000)
|
62
|
+
boxplot_numsteps_problem(d, "MinBealeFunction", 50000)
|
63
|
+
effect.size(d, "MinBealeFunction", 50000, "RL4", "RL5")
|
64
|
+
|
65
|
+
boxplot_numsteps_problem(d, "MinEasomFunction", 1000)
|
66
|
+
boxplot_numsteps_problem(d, "MinEasomFunction", 5000)
|
67
|
+
boxplot_numsteps_problem(d, "MinEasomFunction", 10000)
|
68
|
+
boxplot_numsteps_problem(d, "MinEasomFunction", 25000)
|
69
|
+
boxplot_numsteps_problem(d, "MinEasomFunction", 50000)
|
70
|
+
|
71
|
+
boxplot_numsteps_problem(d, "MinEggHolderFunction", 1000)
|
72
|
+
boxplot_numsteps_problem(d, "MinEggHolderFunction", 5000)
|
73
|
+
boxplot_numsteps_problem(d, "MinEggHolderFunction", 10000)
|
74
|
+
boxplot_numsteps_problem(d, "MinEggHolderFunction", 25000)
|
75
|
+
boxplot_numsteps_problem(d, "MinEggHolderFunction", 50000)
|
76
|
+
|
77
|
+
boxplot_numsteps_problem(d, "MinOmniTest", 25000)
|
78
|
+
effect.size(d, "MinOmniTest", 50000, "RL5", "PS15")
|
@@ -0,0 +1,264 @@
|
|
1
|
+
$: << "lib"
|
2
|
+
$: << "../../lib"
|
3
|
+
require 'feldtruby/optimize/differential_evolution'
|
4
|
+
|
5
|
+
# Compare different samplers and their effect on the quality of evolved
|
6
|
+
# solutions.
|
7
|
+
|
8
|
+
$NumSteps = (ARGV[0] && ARGV[0] =~ /^\d+/) ? ARGV[0].to_i : 10_000
|
9
|
+
|
10
|
+
NumSteps1 = [1_000, 5_000, 10_000, 25_000]
|
11
|
+
NumSteps2 = [5_000, 10_000, 25_000, 50_000]
|
12
|
+
|
13
|
+
NumSteps = NumSteps1
|
14
|
+
#NumSteps = NumSteps2
|
15
|
+
|
16
|
+
SamplerRadiuses1 = [
|
17
|
+
["PopulationSampler", 15],
|
18
|
+
["RadiusLimitedPopulationSampler", 5],
|
19
|
+
["RadiusLimitedPopulationSampler", 10],
|
20
|
+
["RadiusLimitedPopulationSampler", 15],
|
21
|
+
["RadiusLimitedPopulationSampler", 20],
|
22
|
+
["RadiusLimitedPopulationSampler", 25],
|
23
|
+
["RadiusLimitedPopulationSampler", 50],
|
24
|
+
]
|
25
|
+
|
26
|
+
SamplerRadiuses2 = (4..30).map do |radius|
|
27
|
+
["RadiusLimitedPopulationSampler", radius]
|
28
|
+
end + [["PopulationSampler", 15]]
|
29
|
+
|
30
|
+
SamplerRadiuses = SamplerRadiuses1
|
31
|
+
#SamplerRadiuses = SamplerRadiuses2
|
32
|
+
|
33
|
+
NumRepetitionsPerSampler = 5
|
34
|
+
|
35
|
+
# This is Lévi function number 13 as stated on the page:
|
36
|
+
# http://en.wikipedia.org/wiki/Test_functions_for_optimization
|
37
|
+
# It has a global minima at f(1,1) = 0. -10 <= x,y <= 10
|
38
|
+
class MinLeviFunctionNum13 < FeldtRuby::Optimize::Objective
|
39
|
+
TwoPi = 2*Math::PI
|
40
|
+
ThreePi = 3*Math::PI
|
41
|
+
|
42
|
+
def objective_min_levi13(candidate)
|
43
|
+
x, y = candidate[0], candidate[1]
|
44
|
+
sin_3pi_x = Math.sin(ThreePi * x)
|
45
|
+
sin_3pi_y = Math.sin(ThreePi * y)
|
46
|
+
sin_2pi_y = Math.sin(TwoPi * y)
|
47
|
+
x_min1 = x - 1.0
|
48
|
+
y_min1 = y - 1.0
|
49
|
+
|
50
|
+
(sin_3pi_x * sin_3pi_x) +
|
51
|
+
(x_min1 * x_min1) * (1 + (sin_3pi_y * sin_3pi_y)) +
|
52
|
+
(y_min1 * y_min1) * (1 + (sin_3pi_y * sin_2pi_y))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# This is Beale's function as stated on the page:
|
57
|
+
# http://en.wikipedia.org/wiki/Test_functions_for_optimization
|
58
|
+
# It has a global minima at f(3,0.5) = 0. -4.5 <= x,y <= 4.5
|
59
|
+
class MinBealeFunction < FeldtRuby::Optimize::Objective
|
60
|
+
def objective_min_beales_func(candidate)
|
61
|
+
x, y = candidate[0], candidate[1]
|
62
|
+
|
63
|
+
t1 = 1.5 - x + (x*y)
|
64
|
+
t2 = 2.25 - x + (x*y*y)
|
65
|
+
t3 = 2.625 - x + (x*y*y*y)
|
66
|
+
|
67
|
+
(t1*t1) + (t2*t2) + (t3*t3)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# This is Easom's function as stated on the page:
|
72
|
+
# http://en.wikipedia.org/wiki/Test_functions_for_optimization
|
73
|
+
# It has a global minima at f(3,0.5) = 0. -4.5 <= x,y <= 4.5
|
74
|
+
class MinEasomFunction < FeldtRuby::Optimize::Objective
|
75
|
+
def objective_min_easom_func(candidate)
|
76
|
+
x, y = candidate[0], candidate[1]
|
77
|
+
|
78
|
+
f1 = Math.cos(x)
|
79
|
+
|
80
|
+
f2 = Math.cos(y)
|
81
|
+
|
82
|
+
x_min_pi = x - Math::PI
|
83
|
+
y_min_pi = y - Math::PI
|
84
|
+
|
85
|
+
f3 = Math.exp(-(x_min_pi*x_min_pi + y_min_pi*y_min_pi))
|
86
|
+
|
87
|
+
(-f1) * f2 * f3
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# EggHolder function as stated on the page:
|
92
|
+
# http://en.wikipedia.org/wiki/Test_functions_for_optimization
|
93
|
+
class MinEggHolderFunction < FeldtRuby::Optimize::Objective
|
94
|
+
def objective_min_eggholder(candidate)
|
95
|
+
x, y = candidate[0], candidate[1]
|
96
|
+
|
97
|
+
f1 = y + 47.0
|
98
|
+
f2 = Math.sin( Math.sqrt( (y + (x/2.0) + 47.0).abs ) )
|
99
|
+
t1 = (-f1)*f2
|
100
|
+
|
101
|
+
f3 = Math.sin( Math.sqrt( (x - (y + 47.0)).abs ) )
|
102
|
+
t2 = (-x) * f3
|
103
|
+
|
104
|
+
t1 - t2
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class MinFunctionOfDimension < FeldtRuby::Optimize::Objective
|
109
|
+
attr_accessor :dimension
|
110
|
+
def minimum
|
111
|
+
0.0
|
112
|
+
end
|
113
|
+
def min_solutions
|
114
|
+
@min_solutions ||= ([[0.0] * dimension])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Sphere function as stated in the JADE paper:
|
119
|
+
# http://150.214.190.154/EAMHCO/pdf/JADE.pdf
|
120
|
+
class MinSphere < MinFunctionOfDimension
|
121
|
+
def objective_min_func(x)
|
122
|
+
x.inject(0.0) do |sum, xi|
|
123
|
+
sum + (xi*xi)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Schwefel 2.22 function as stated in the JADE paper:
|
129
|
+
# http://150.214.190.154/EAMHCO/pdf/JADE.pdf
|
130
|
+
class MinSchwefel2_22 < MinFunctionOfDimension
|
131
|
+
def objective_min_func(x)
|
132
|
+
t1 = x.inject(0.0) do |sum, xi|
|
133
|
+
sum + xi.abs
|
134
|
+
end
|
135
|
+
|
136
|
+
t2 = x.inject(0.0) do |mult, xi|
|
137
|
+
mult * xi.abs
|
138
|
+
end
|
139
|
+
|
140
|
+
t1 + t2
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Schwefel 1.2 function as stated in the JADE paper:
|
145
|
+
# http://150.214.190.154/EAMHCO/pdf/JADE.pdf
|
146
|
+
class MinSchwefel1_2 < MinFunctionOfDimension
|
147
|
+
def objective_min_func(x)
|
148
|
+
i = 0
|
149
|
+
sum = 0.0
|
150
|
+
while i < dimension
|
151
|
+
j = 0
|
152
|
+
inner_sum = 0.0
|
153
|
+
while j <= i
|
154
|
+
inner_sum += x[j]
|
155
|
+
j += 1
|
156
|
+
end
|
157
|
+
sum += inner_sum
|
158
|
+
i += 1
|
159
|
+
end
|
160
|
+
|
161
|
+
sum
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Schwefel 2.21 function as stated in the JADE paper:
|
166
|
+
# http://150.214.190.154/EAMHCO/pdf/JADE.pdf
|
167
|
+
class MinSchwefel2_21 < MinFunctionOfDimension
|
168
|
+
def objective_min_func(x)
|
169
|
+
max_so_far = x[0].abs
|
170
|
+
(1...dimension).each do |i|
|
171
|
+
max_so_far = x[i] if (x[i] < max_so_far)
|
172
|
+
end
|
173
|
+
max_so_far
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# This is the OmniTest bi-criteria test function as described in the paper:
|
178
|
+
# Shir et al, "Enhancing Decision Space Diversity in Evolutionary Multiobjective Algorithms", 2009.
|
179
|
+
class MinOmniTest < MinFunctionOfDimension
|
180
|
+
def objective_min_sin(x)
|
181
|
+
x.map {|xi| Math.sin(Math::PI * xi)}.sum
|
182
|
+
end
|
183
|
+
def objective_min_cos(x)
|
184
|
+
x.map {|xi| Math.cos(Math::PI * xi)}.sum
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
Problems1 = [
|
189
|
+
["MinLeviFunctionNum13", ([[-10, 10]] * 2)],
|
190
|
+
["MinBealeFunction", ([[-4.5, 4.5]] * 2)],
|
191
|
+
["MinEasomFunction", ([[-100, 100]] * 2)]
|
192
|
+
]
|
193
|
+
|
194
|
+
Problems2 = [
|
195
|
+
["MinEggHolderFunction", ([[-512, 512]] * 2)]
|
196
|
+
]
|
197
|
+
|
198
|
+
Problems3 = [
|
199
|
+
["MinOmniTest", ([[0, 6]] * 5)]
|
200
|
+
]
|
201
|
+
|
202
|
+
#Problems = Problems1
|
203
|
+
#Problems = Problems2
|
204
|
+
Problems = Problems1 + Problems2
|
205
|
+
#Problems = Problems3
|
206
|
+
|
207
|
+
include FeldtRuby::Optimize
|
208
|
+
|
209
|
+
def best_individual(samplerClass, radius, objectiveKlass, minMaxSpec, numSteps)
|
210
|
+
|
211
|
+
ss = SearchSpace.new_from_min_max_per_variable(minMaxSpec)
|
212
|
+
|
213
|
+
objective = objectiveKlass.new
|
214
|
+
|
215
|
+
de = DEOptimizer.new(objective, ss, {
|
216
|
+
:verbose => true,
|
217
|
+
:maxNumSteps => numSteps,
|
218
|
+
:samplerClass => samplerClass,
|
219
|
+
:samplerRadius => radius})
|
220
|
+
|
221
|
+
start = Time.now
|
222
|
+
best = de.optimize()
|
223
|
+
elapsed_time = Time.now - start
|
224
|
+
|
225
|
+
return best, objective.quality_of(best), elapsed_time
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
tstr = Time.now.strftime("%y%m%d_%H%M%S")
|
230
|
+
|
231
|
+
fh = File.open("results_comparing_samplers_#{tstr}.csv", "w")
|
232
|
+
|
233
|
+
# Find the max number of vars for one of the problems
|
234
|
+
MaxNumVars = Problems.map {|p| p[1].length}.max
|
235
|
+
|
236
|
+
ColNamesForVariables = (0...MaxNumVars).map {|i| "X#{i}"}.join(",")
|
237
|
+
|
238
|
+
fh.puts "Problem,Sampler,Radius,Time,NumSteps,Q,#{ColNamesForVariables}"
|
239
|
+
|
240
|
+
Problems.each do |problem, minMaxSpec|
|
241
|
+
|
242
|
+
objectiveKlass = eval problem
|
243
|
+
|
244
|
+
NumSteps.each do |num_steps|
|
245
|
+
|
246
|
+
SamplerRadiuses.each do |sampler, radius|
|
247
|
+
sampler_klass = eval "FeldtRuby::Optimize::#{sampler}"
|
248
|
+
|
249
|
+
NumRepetitionsPerSampler.times do
|
250
|
+
best, qv, elapsed_time = best_individual sampler_klass, radius, objectiveKlass, minMaxSpec, num_steps
|
251
|
+
|
252
|
+
best_str = best.to_a.map {|xi| xi.to_s}.join(",")
|
253
|
+
|
254
|
+
s = "#{problem},#{sampler},#{radius},#{elapsed_time},#{num_steps},#{qv.value},#{best_str}"
|
255
|
+
fh.puts s
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
fh.close
|