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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f017a746cfb0c942893d7207ddcd0ec3d3a2a252
4
- data.tar.gz: 475222949c01be1ae9dbb5678b4f2da00bf5a877
3
+ metadata.gz: b5558f3b77d1f52c3bb73f77ab79755b9d8e8f20
4
+ data.tar.gz: 1d6e7c4cea54211d5487b41b71710ea30827ceb8
5
5
  SHA512:
6
- metadata.gz: b85a1f419930ec29d072227bfa3423b3088f2befc4755d60df2cf8f870407d35cb84b2684074917c38aa3904e697476bc6ea9d5ecb633e0692e9a2c274fb6c02
7
- data.tar.gz: f825a6ee4384822a133f39df4f8c1867f42e611e2cdb307bcf2eaf3771860435f2ed1cd7440210b0841c2040f83e4affd1744023350154e40095dd272679b6d1
6
+ metadata.gz: d7f2ff3e1edcacd55278c11d228eced97c128ce1628f55f5edb30aee3fdfb6c2a7c676ac62860a62e5cfd33bd588eba795d50f489becbaae592bb63b36f8b07b
7
+ data.tar.gz: 2397c74ee5a6eea1c250b9481ace101ed6ecc58990649b2fa6d10aaee73136a5b5e758ccd7689c807f1283f49493c7e3ac1987dea11b37fe4fe262f6e8474020
@@ -9,7 +9,7 @@ module FeldtRuby
9
9
  class Logger
10
10
  DefaultParams = {
11
11
  :verbose => false,
12
- :printFrequency => 0.4 # Minimum seconds between consecutive messages printed for the same event type
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", true
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
- # Building block for mutation strategies.
146
- module DE_X_1_StrategyBuildingBlock
147
- # We need 0 target parents and 2 other parents. Note that we must sample a target parent
148
- # also even though it is not used in the mutation.
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 = get_candidate(donorParentsIndices[-1])
160
- p3 + scale_factor(targetIndex) * difference_vector(donorParentsIndices[0...-1])
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
- # The most-used DE/rand/1 mutation strategy.
165
- module DE_MutationStrategy_Rand_1
166
- include DE_X_1_StrategyBuildingBlock
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
- # We need one more parent in the Rand strategy than in the others, but
169
- # we can reuse the difference vector generation. So partial reuse here
170
- # NOTE! Order of inclusion is critical!!!
171
- def num_parents_to_sample; 4; end
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
- include DE_Rand_X_StrategyBuildingBlock
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
- # The default DEOptimizer uses
177
- # Bounding = random bouding within the search space
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 = Rand-1
181
- class DEOptimizer < DEOptimizerBase
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 DE_MutationStrategy_Rand_1
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},
@@ -294,9 +294,6 @@ class Objective
294
294
  :type_of_improvement => typeOfReset
295
295
  }, "Better candidate found for goal #{goal_methods[index]}"
296
296
 
297
- # Reset the best object since we have a new scale
298
- @best_candidate = nil
299
-
300
297
  end
301
298
 
302
299
  inc_version_number
@@ -1,3 +1,3 @@
1
1
  module FeldtRuby
2
- VERSION = "0.4.4"
2
+ VERSION = "0.4.5"
3
3
  end
@@ -169,7 +169,7 @@ end
169
169
  class MinEggHolder < Min2DSingleObjectiveFunc
170
170
  def minimum
171
171
  # -959.6407
172
- -963.5808501270542
172
+ -963.5808501270571
173
173
  end
174
174
 
175
175
  def min_solutions
@@ -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
- def best_from_de_on_objective(objective, dimensions, numSteps = 25_000, verbose = false)
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 = DEOptimizer.new(objective, ss, {:verbose => verbose,
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
- objective = MinEasom.new
78
- ss = objective.search_space
79
- de = DEOptimizer.new(objective, ss, {:verbose => false,
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
- objective = MinEggHolder.new
95
- ss = objective.search_space
96
- de = DEOptimizer.new(objective, ss, {:verbose => false,
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feldtruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Feldt