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
@@ -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.first != target
65
- @logger.note_new_better("Trial vector was better", *best)
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.first]
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 = 1000)
18
+ def initialize(maxSteps = 10_000)
19
19
  @max_steps = maxSteps
20
20
  end
21
21
  def terminate?(optimizer)