feldtruby 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/feldtruby/logger.rb +1 -1
- data/lib/feldtruby/optimize/differential_evolution.rb +37 -28
- data/lib/feldtruby/optimize/objective.rb +0 -3
- data/lib/feldtruby/version.rb +1 -1
- data/test/long_running/single_objective_problems.rb +1 -1
- data/test/long_running/test_single_objective_optimization.rb +13 -25
- data/test/test_optimize_differential_evolution.rb +22 -0
- 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: b5558f3b77d1f52c3bb73f77ab79755b9d8e8f20
|
4
|
+
data.tar.gz: 1d6e7c4cea54211d5487b41b71710ea30827ceb8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7f2ff3e1edcacd55278c11d228eced97c128ce1628f55f5edb30aee3fdfb6c2a7c676ac62860a62e5cfd33bd588eba795d50f489becbaae592bb63b36f8b07b
|
7
|
+
data.tar.gz: 2397c74ee5a6eea1c250b9481ace101ed6ecc58990649b2fa6d10aaee73136a5b5e758ccd7689c807f1283f49493c7e3ac1987dea11b37fe4fe262f6e8474020
|
data/lib/feldtruby/logger.rb
CHANGED
@@ -9,7 +9,7 @@ module FeldtRuby
|
|
9
9
|
class Logger
|
10
10
|
DefaultParams = {
|
11
11
|
:verbose => false,
|
12
|
-
:printFrequency => 0.
|
12
|
+
:printFrequency => 0.3 # Minimum seconds between consecutive messages printed for the same event type
|
13
13
|
}
|
14
14
|
|
15
15
|
UnixEpoch = Time.at(0)
|
@@ -67,7 +67,7 @@ class DEOptimizerBase < EvolutionaryOptimizer
|
|
67
67
|
"Trial Quality" => @objective.quality_of(trial),
|
68
68
|
"Target" => target,
|
69
69
|
"Target Quality" => @objective.quality_of(target)
|
70
|
-
}, "DE (step #{@num_optimization_steps}): Trial vector was better than target vector"
|
70
|
+
}, "DE (step #{@num_optimization_steps}): Trial vector was better than target vector"
|
71
71
|
update_candidate_in_population(target_index, trial)
|
72
72
|
feedback_on_trial_vs_target(trial, target, true)
|
73
73
|
else
|
@@ -142,49 +142,58 @@ module DE_CrossoverStrategy_Binomial
|
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
-
#
|
146
|
-
module
|
147
|
-
# We need
|
148
|
-
|
149
|
-
def num_parents_to_sample; 3; end
|
150
|
-
|
151
|
-
def difference_vector(donorParentsIndices)
|
152
|
-
p1, p2 = get_candidates_with_indices(donorParentsIndices)
|
153
|
-
(p1 - p2)
|
154
|
-
end
|
155
|
-
end
|
145
|
+
# The most-used DE/rand/1/* mutation strategy.
|
146
|
+
module DE_MutationStrategy_Rand_1
|
147
|
+
# We need three parents for donor vector. And then the target, so 1+3 in total.
|
148
|
+
def num_parents_to_sample; 4; end
|
156
149
|
|
157
|
-
module DE_Rand_X_StrategyBuildingBlock
|
158
150
|
def mutate(targetIndex, donorParentsIndices)
|
159
|
-
p3 =
|
160
|
-
p3 + scale_factor(targetIndex) *
|
151
|
+
p1, p2, p3 = get_candidates_with_indices(donorParentsIndices)
|
152
|
+
p3 + (scale_factor(targetIndex) * (p1 - p2))
|
161
153
|
end
|
162
154
|
end
|
163
155
|
|
164
|
-
#
|
165
|
-
|
166
|
-
|
156
|
+
# DE/rand/1/bin uses
|
157
|
+
# Bounding = random bounding within the search space
|
158
|
+
# Update = no updates based on feedback
|
159
|
+
# Crossover = Classic binomial
|
160
|
+
# Mutation = Rand-1
|
161
|
+
class DEOptimizer_Rand_1_Bin < DEOptimizerBase
|
162
|
+
include DE_BoundingStrategy_RandomWithinSearchSpace
|
163
|
+
include DE_UpdateStrategy_NoFeedbackUpdates
|
164
|
+
include DE_CrossoverStrategy_Binomial
|
165
|
+
include DE_MutationStrategy_Rand_1
|
166
|
+
end
|
167
167
|
|
168
|
-
|
169
|
-
|
170
|
-
#
|
171
|
-
def num_parents_to_sample;
|
168
|
+
# The DE/best/1/* mutation strategy.
|
169
|
+
module DE_MutationStrategy_Best_1
|
170
|
+
# We need two parents for donor vector. And then the target, so 1+2 in total.
|
171
|
+
def num_parents_to_sample; 3; end
|
172
172
|
|
173
|
-
|
173
|
+
def mutate(targetIndex, donorParentsIndices)
|
174
|
+
p1, p2 = get_candidates_with_indices(donorParentsIndices)
|
175
|
+
candidate_from_array(best) + (scale_factor(targetIndex) * (p1 - p2))
|
176
|
+
end
|
174
177
|
end
|
175
178
|
|
176
|
-
#
|
177
|
-
# Bounding = random
|
179
|
+
# DE/best/1/bin uses
|
180
|
+
# Bounding = random bounding within the search space
|
178
181
|
# Update = no updates based on feedback
|
179
182
|
# Crossover = Classic binomial
|
180
|
-
# Mutation =
|
181
|
-
class
|
183
|
+
# Mutation = Best-1
|
184
|
+
class DEOptimizer_Best_1_Bin < DEOptimizerBase
|
182
185
|
include DE_BoundingStrategy_RandomWithinSearchSpace
|
183
186
|
include DE_UpdateStrategy_NoFeedbackUpdates
|
184
187
|
include DE_CrossoverStrategy_Binomial
|
185
|
-
include
|
188
|
+
include DE_MutationStrategy_Best_1
|
186
189
|
end
|
187
190
|
|
191
|
+
# DE/rand/1/bin is the default DE optimizer since it does not converge too
|
192
|
+
# quickly but is generally good. For many problems the DEOptimizer_Best_1_Bin
|
193
|
+
# gives better results faster though.
|
194
|
+
DEOptimizer = DEOptimizer_Rand_1_Bin
|
195
|
+
#DEOptimizer = DEOptimizer_Best_1_Bin
|
196
|
+
|
188
197
|
# Optimize the _numVariables_ between the _min_ and _max_ values given _costFunction_.
|
189
198
|
# Default is to minimize.
|
190
199
|
def self.optimize(min, max, options = {:verbose => true},
|
data/lib/feldtruby/version.rb
CHANGED
@@ -19,10 +19,15 @@ module MiniTest::Expectations
|
|
19
19
|
infect_an_assertion :assert_close_to_one_solution, :must_be_close_to_one_solution_of
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
# Note! We have set the numSteps below so that DEOptimizer_Rand_1_Bin can converge
|
23
|
+
# to a solution. However, for most of these optimization problems
|
24
|
+
# DEOptimizer_Best_1_Bin converges much faster, and can thus be used.
|
25
|
+
|
26
|
+
def best_from_de_on_objective(objective, dimensions, numSteps = 25_000,
|
27
|
+
verbose = false, optimizer = FeldtRuby::Optimize::DEOptimizer_Rand_1_Bin)
|
23
28
|
objective.dimensions = dimensions if objective.respond_to?(:dimensions=)
|
24
29
|
ss = objective.search_space
|
25
|
-
de =
|
30
|
+
de = optimizer.new(objective, ss, {:verbose => verbose,
|
26
31
|
:maxNumSteps => numSteps})
|
27
32
|
|
28
33
|
start_time = Time.now
|
@@ -74,34 +79,17 @@ end
|
|
74
79
|
|
75
80
|
describe "Easom function" do
|
76
81
|
it 'can optimize the Easom function' do
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
:maxNumSteps => 30_000, :printFrequency => 0.0,
|
81
|
-
:samplerRadius => 5})
|
82
|
-
best = de.optimize().to_a
|
83
|
-
|
84
|
-
val = objective.calc_func(best)
|
85
|
-
val.must_be_close_to objective.minimum
|
86
|
-
val.must_be :>=, objective.minimum
|
87
|
-
|
88
|
-
best.must_be_close_to_one_solution_of objective, 0.01
|
82
|
+
best, obj, time = best_from_de_on_objective MinBeale.new, nil, 10_000, false, FeldtRuby::Optimize::DEOptimizer_Best_1_Bin
|
83
|
+
best.must_be_close_to_one_solution_of obj
|
84
|
+
time.must_be :<, 1.5
|
89
85
|
end
|
90
86
|
end
|
91
87
|
|
92
88
|
describe "EggHolder function" do
|
93
89
|
it 'can optimize the Eggholder function' do
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
:maxNumSteps => 25_000, :samplerRadius => 6})
|
98
|
-
best = de.optimize().to_a
|
99
|
-
|
100
|
-
val = objective.calc_func(best)
|
101
|
-
val.must_be_close_to objective.minimum
|
102
|
-
val.must_be :>=, objective.minimum
|
103
|
-
|
104
|
-
best.must_be_close_to_one_solution_of objective, 0.01
|
90
|
+
best, obj, time = best_from_de_on_objective MinEggHolder.new, nil, 10_000, false, FeldtRuby::Optimize::DEOptimizer_Best_1_Bin
|
91
|
+
best.must_be_close_to_one_solution_of obj
|
92
|
+
time.must_be :<, 1.5
|
105
93
|
end
|
106
94
|
end
|
107
95
|
|
@@ -41,4 +41,26 @@ describe "DifferentialEvolution" do
|
|
41
41
|
de2.best.sum.must_be :<=, 0.40
|
42
42
|
de2.num_optimization_steps.must_equal 1234
|
43
43
|
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "DE/best/1/bin" do
|
47
|
+
it "works for rms of small vector" do
|
48
|
+
s2 = SearchSpace.new_symmetric(2, 1)
|
49
|
+
o1 = MinimizeRMS.new
|
50
|
+
de1 = DEOptimizer_Best_1_Bin.new(o1, s2, {:verbose => false, :maxNumSteps => 1000})
|
51
|
+
de1.optimize()
|
52
|
+
# Very unlikely we get a number over 0.30 (2 elements) after 1000 steps...
|
53
|
+
de1.best.sum.must_be :<=, 0.30
|
54
|
+
de1.num_optimization_steps.must_equal 1000
|
55
|
+
end
|
56
|
+
|
57
|
+
it "works for rms and sum of small vector and with more steps" do
|
58
|
+
s4 = SearchSpace.new_symmetric(4, 1)
|
59
|
+
o2 = MinimizeRMSAndSum.new
|
60
|
+
de2 = DEOptimizer_Best_1_Bin.new(o2, s4, {:verbose => false, :maxNumSteps => 1234})
|
61
|
+
de2.optimize()
|
62
|
+
# Very unlikely we get a number over 0.40 (4 elements)...
|
63
|
+
de2.best.sum.must_be :<=, 0.40
|
64
|
+
de2.num_optimization_steps.must_equal 1234
|
65
|
+
end
|
44
66
|
end
|