feldtruby 0.3.16 → 0.3.18
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'feldtruby/optimize/optimizer'
|
2
2
|
require 'feldtruby/math/rand'
|
3
3
|
require 'feldtruby/vector'
|
4
|
+
require 'feldtruby/logger'
|
4
5
|
|
5
6
|
module FeldtRuby::Optimize
|
6
7
|
|
7
8
|
# Common to many Evolutionary Computation optimizers
|
8
|
-
class EvolutionaryOptimizer < PopulationBasedOptimizer; end
|
9
|
+
class EvolutionaryOptimizer < FeldtRuby::Optimize::PopulationBasedOptimizer; end
|
9
10
|
|
10
11
|
# Base class for Differential Evolution (DE) for continuous, real-valued optimization.
|
11
12
|
# Since there are many different DE variants this is the base class
|
@@ -57,12 +58,13 @@ class DEOptimizerBase < EvolutionaryOptimizer
|
|
57
58
|
def optimization_step()
|
58
59
|
trial, target, target_index = generate_trial_candidate_and_target()
|
59
60
|
|
60
|
-
# We get [candidate, qualityValue, subQualityValues] for each vector
|
61
61
|
best, worst = objective.rank_candidates([target, trial])
|
62
62
|
|
63
63
|
# Supplant the target vector with the trial vector if better
|
64
|
-
if best
|
65
|
-
|
64
|
+
if best != target
|
65
|
+
logger.log_data :better_candidate_found, {
|
66
|
+
:better => best,
|
67
|
+
:quality => @objective.quality_of(best)}, "Trial vector was better"
|
66
68
|
trial_better = true
|
67
69
|
update_candidate_in_population(target_index, trial)
|
68
70
|
else
|
@@ -72,7 +74,7 @@ class DEOptimizerBase < EvolutionaryOptimizer
|
|
72
74
|
# Give feedback to strategy since some strategies use this to self-adapt
|
73
75
|
feedback_on_trial_vs_target(trial, target, trial_better)
|
74
76
|
|
75
|
-
[best
|
77
|
+
[best]
|
76
78
|
end
|
77
79
|
|
78
80
|
#####################################
|
@@ -183,4 +185,26 @@ class DEOptimizer < DEOptimizerBase
|
|
183
185
|
include DE_MutationStrategy_Rand_1
|
184
186
|
end
|
185
187
|
|
188
|
+
# Optimize the _numVariables_ between the _min_ and _max_ values given _costFunction_.
|
189
|
+
# Default is to minimize.
|
190
|
+
def self.optimize(min, max, options = {:verbose => true},
|
191
|
+
objectiveFuncClass = FeldtRuby::Optimize::ObjectiveMinimizeBlock, &costFunction)
|
192
|
+
objective = objectiveFuncClass.new(&costFunction)
|
193
|
+
num_vars = costFunction.arity
|
194
|
+
search_space = SearchSpace.new_from_min_max(num_vars, min, max)
|
195
|
+
optimizer = DEOptimizer.new(objective, search_space, options)
|
196
|
+
optimizer.optimize()
|
197
|
+
optimizer.best.to_a
|
198
|
+
end
|
199
|
+
|
200
|
+
# Short hand wrapper for function minimization.
|
201
|
+
def self.minimize(min, max, options = {}, &costFunction)
|
202
|
+
optimize(min, max, options, &costFunction)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Short hand wrapper for function maximization.
|
206
|
+
def self.maximize(min, max, options = {}, &costFunction)
|
207
|
+
optimize(min, max, options, FeldtRuby::Optimize::ObjectiveMaximizeBlock, &costFunction)
|
208
|
+
end
|
209
|
+
|
186
210
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'feldtruby/optimize'
|
2
|
+
|
3
|
+
module FeldtRuby::Optimize
|
4
|
+
|
5
|
+
# This keeps a record of the best/elite candidate solutions found during
|
6
|
+
# an optimization search. It keeps separate top lists per goal being optimized
|
7
|
+
# as well as for the aggregate quality value (fitness) itself. The top lists
|
8
|
+
# are all sorted to allow for fast checks and insertion.
|
9
|
+
class EliteArchive
|
10
|
+
DefaultParams = {
|
11
|
+
:NumTopPerGoal => 10,
|
12
|
+
:NumTopAggregate => 25
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_reader :objective, :top_per_goal, :best
|
16
|
+
|
17
|
+
def initialize(objective, options = DefaultParams.clone)
|
18
|
+
@objective = objective
|
19
|
+
@options = options
|
20
|
+
init_top_lists
|
21
|
+
end
|
22
|
+
|
23
|
+
# A top list is an array of a fixed size that saves the top candidates
|
24
|
+
# based on their quality values.
|
25
|
+
class GlobalTopList
|
26
|
+
def initialize(maxSize, objective)
|
27
|
+
@max_size =maxSize
|
28
|
+
@top_list = Array.new
|
29
|
+
@objective = objective
|
30
|
+
end
|
31
|
+
def length; @top_list.length; end
|
32
|
+
|
33
|
+
def [](index)
|
34
|
+
@top_list[index]
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(candidate)
|
38
|
+
last = @top_list.last
|
39
|
+
#puts "In #{self},\nlast = #{last}, candidate = #{candidate}, top_list = #{@top_list}"
|
40
|
+
if @top_list.length < @max_size || last.nil? || is_better_than?(candidate, last)
|
41
|
+
@top_list.pop if @top_list.length >= @max_size
|
42
|
+
@top_list << candidate
|
43
|
+
@top_list = sort_top_list
|
44
|
+
end
|
45
|
+
#puts "top_list = #{@top_list}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def is_better_than?(candidate1, candidate2)
|
49
|
+
@objective.is_better_than?(candidate1, candidate2)
|
50
|
+
end
|
51
|
+
|
52
|
+
def sort_top_list
|
53
|
+
@top_list.sort_by {|c| @objective.quality_of(c).value}
|
54
|
+
end
|
55
|
+
|
56
|
+
def inspect
|
57
|
+
self.class.inspect + @top_list.inspect
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class GoalTopList < GlobalTopList
|
62
|
+
def initialize(maxSize, objective, goalIndex)
|
63
|
+
super(maxSize, objective)
|
64
|
+
@index = goalIndex
|
65
|
+
end
|
66
|
+
def is_better_than?(candidate1, candidate2)
|
67
|
+
@objective.is_better_than_for_goal?(@index, candidate1, candidate2)
|
68
|
+
end
|
69
|
+
def sort_top_list
|
70
|
+
@top_list.sort_by {|c|
|
71
|
+
qv = @objective.quality_of(c)
|
72
|
+
qv.sub_quality(@index, true) # We want the sub quality value posed as a minimization goal regardless of whether it is a min or max goal
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def init_top_lists
|
78
|
+
@top_per_goal = Array.new
|
79
|
+
@objective.num_goals.times do |i|
|
80
|
+
@top_per_goal << GoalTopList.new(@options[:NumTopPerGoal], @objective, i)
|
81
|
+
end
|
82
|
+
@best = GlobalTopList.new(@options[:NumTopAggregate], @objective)
|
83
|
+
end
|
84
|
+
|
85
|
+
def add(candidate)
|
86
|
+
@best.add candidate
|
87
|
+
@top_per_goal.each {|tl| tl.add(candidate)}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -15,7 +15,7 @@ end
|
|
15
15
|
class FeldtRuby::Optimize::MaxStepsTerminationCriterion < FeldtRuby::Optimize::TerminationCriterion
|
16
16
|
attr_accessor :max_steps
|
17
17
|
|
18
|
-
def initialize(maxSteps =
|
18
|
+
def initialize(maxSteps = 10_000)
|
19
19
|
@max_steps = maxSteps
|
20
20
|
end
|
21
21
|
def terminate?(optimizer)
|