feldtruby 0.4.4 → 0.4.5
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.
- 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
         
     |