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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile.lock +9 -2
  3. data/Rakefile +8 -0
  4. data/feldtruby.gemspec +6 -0
  5. data/lib/feldtruby/annotations.rb +10 -0
  6. data/lib/feldtruby/array/basic_stats.rb +3 -1
  7. data/lib/feldtruby/array/permutations_and_subsets.rb +17 -0
  8. data/lib/feldtruby/float.rb +23 -0
  9. data/lib/feldtruby/logger.rb +216 -30
  10. data/lib/feldtruby/minitest_extensions.rb +0 -1
  11. data/lib/feldtruby/mongodb.rb +16 -0
  12. data/lib/feldtruby/mongodb_logger.rb +245 -0
  13. data/lib/feldtruby/optimize/differential_evolution.rb +29 -5
  14. data/lib/feldtruby/optimize/elite_archive.rb +91 -0
  15. data/lib/feldtruby/optimize/max_steps_termination_criterion.rb +1 -1
  16. data/lib/feldtruby/optimize/objective.rb +343 -222
  17. data/lib/feldtruby/optimize/optimizer.rb +138 -60
  18. data/lib/feldtruby/optimize/search_space.rb +10 -0
  19. data/lib/feldtruby/optimize.rb +1 -26
  20. data/lib/feldtruby/statistics.rb +74 -3
  21. data/lib/feldtruby/time.rb +19 -0
  22. data/lib/feldtruby/version.rb +1 -1
  23. data/old/event_logger.rb +682 -0
  24. data/spikes/comparing_samplers_on_classic_optimization_functions/analyze_sampler_comparison_results.R +78 -0
  25. data/spikes/comparing_samplers_on_classic_optimization_functions/compare_samplers.rb +264 -0
  26. data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_130405_175934.csv +561 -0
  27. data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder.csv +11201 -0
  28. data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_levi13_beale_easom_eggholder_all_radii_4_to_30.csv +44801 -0
  29. data/spikes/comparing_samplers_on_classic_optimization_functions/results_comparing_samplers_omnitest.csv +1401 -0
  30. data/spikes/mongodb_logger.rb +47 -0
  31. data/spikes/simple_de_run.rb +32 -0
  32. data/test/helper.rb +17 -1
  33. data/test/test_array_basic_stats.rb +5 -1
  34. data/test/test_array_permutations_and_subsets.rb +23 -0
  35. data/test/test_float.rb +15 -0
  36. data/test/test_html_doc_getter.rb +1 -1
  37. data/test/test_logger.rb +86 -48
  38. data/test/test_mongodb_logger.rb +116 -0
  39. data/test/test_object_annotations.rb +14 -0
  40. data/test/test_optimize.rb +7 -6
  41. data/test/test_optimize_differential_evolution.rb +21 -19
  42. data/test/test_optimize_elite_archive.rb +85 -0
  43. data/test/test_optimize_objective.rb +237 -74
  44. data/test/test_optimize_populationbasedoptimizer.rb +72 -6
  45. data/test/test_optimize_random_search.rb +0 -17
  46. data/test/test_optimize_search_space.rb +15 -0
  47. data/test/test_statistics.rb +30 -4
  48. data/test/test_time.rb +22 -0
  49. data/test/tmp_shorter.csv +200 -0
  50. 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