feldtruby 0.4.1 → 0.4.2

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: 0aea61457b6e6c7b8258675bed056af881761d67
4
- data.tar.gz: b726de556b3d1c6e5471f88433bf0117847400e8
3
+ metadata.gz: 3a76753a45218658033069292166e1f2a6632958
4
+ data.tar.gz: f7885cd0eece07094aca1d27da9da38e9ddbf51f
5
5
  SHA512:
6
- metadata.gz: dd59de72274a8ad60e97f0753e13449b77c1f4da793a78a20b16103e36f01132916f1f4616638a5430868877e14fd7ae4b87d8f6fc33df1072c85aab9fd273fa
7
- data.tar.gz: 67cb9c8b514e6d4139842fb0750854687a952957f1a8650c33173fc068f93d189ffcb23821d3bed0f3cf0704eb29b570c6e4ac5d781ed9a4445a17cd463d5e58
6
+ metadata.gz: 96eef547a76262a695fc9480abf6b672b5536881953754ee5b8461de00fa08df05718c5b3e3e40894d4c4d65f527802cec3f11e695a4ca3e9d5b55ba24b2d9b8
7
+ data.tar.gz: db581f0014c8252980e263db25eacc6804723022d8b08130678a2cdf0f1711baf1118fbb26e710101e9225b2ff6ea00fb526be987017e2539d6f403acee8d95a
@@ -41,7 +41,7 @@ class Objective
41
41
 
42
42
  attr_reader :global_min_values_per_goal, :global_max_values_per_goal
43
43
 
44
- def initialize(qualityAggregator = WeightedSumAggregator.new,
44
+ def initialize(qualityAggregator = MeanWeigthedGlobalRatios.new, #WeightedSumAggregator.new,
45
45
  comparator = LowerAggregateQualityIsBetterComparator.new)
46
46
 
47
47
  # A quality aggregator maps the goal values of a candidate to a single number.
@@ -360,12 +360,13 @@ end
360
360
  # P. J. Bentley and J. P. Wakefield, "Finding Acceptable Solutions in the
361
361
  # Pareto-Optimal Range using Multiobjective Genetic Algorithms", 1997
362
362
  # http://eprints.hud.ac.uk/4052/1/PB_%26_JPW_1997_Finding_Acceptable_Solutions.htm
363
- # with the difference that that lower values indicate better quality.
363
+ # with the difference that lower values indicate better quality and we use
364
+ # mean instead of sum, and thus call it MWGR.
364
365
  # It is the weighted sum of the ratios to the best so far for each goal.
365
366
  # One of its benefits is that one need not sort individuals in relation to
366
367
  # their peers; the aggregate fitness value is fully determined by the individual
367
368
  # and the global min and max values for each objective.
368
- class Objective::SumOfWeigthedGlobalRatios < Objective::WeightedSumAggregator
369
+ class Objective::MeanWeigthedGlobalRatios < Objective::WeightedSumAggregator
369
370
  def ratio(index, value, min, max)
370
371
  return 1000.0 if value == nil # We heavily penalize if one sub-quality could not be calculated. Max is otherwise 1.0.
371
372
  if objective.is_min_goal?(index)
@@ -1,3 +1,3 @@
1
1
  module FeldtRuby
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -32,22 +32,6 @@ SamplerRadiuses = SamplerRadiuses1
32
32
 
33
33
  NumRepetitionsPerSampler = 5
34
34
 
35
- # Schwefel 2.22 function as stated in the JADE paper:
36
- # http://150.214.190.154/EAMHCO/pdf/JADE.pdf
37
- class MinSchwefel2_22 < MinFunctionOfDimension
38
- def objective_min_func(x)
39
- t1 = x.inject(0.0) do |sum, xi|
40
- sum + xi.abs
41
- end
42
-
43
- t2 = x.inject(0.0) do |mult, xi|
44
- mult * xi.abs
45
- end
46
-
47
- t1 + t2
48
- end
49
- end
50
-
51
35
  # Schwefel 1.2 function as stated in the JADE paper:
52
36
  # http://150.214.190.154/EAMHCO/pdf/JADE.pdf
53
37
  class MinSchwefel1_2 < MinFunctionOfDimension
@@ -20,65 +20,55 @@ module MiniTest::Expectations
20
20
  end
21
21
 
22
22
  def best_from_de_on_objective(objective, dimensions, numSteps = 25_000, verbose = false)
23
- objective.dimensions = dimensions
23
+ objective.dimensions = dimensions if objective.respond_to?(:dimensions=)
24
24
  ss = objective.search_space
25
25
  de = DEOptimizer.new(objective, ss, {:verbose => verbose,
26
26
  :maxNumSteps => numSteps})
27
+
28
+ start_time = Time.now
27
29
  best = de.optimize().to_a
30
+ elapsed = Time.now - start_time
28
31
 
29
32
  val = objective.calc_func(best)
30
33
  val.must_be_close_to objective.minimum
31
34
  val.must_be :>, objective.minimum
32
35
 
33
- return best, objective
36
+ return best, objective, elapsed
34
37
  end
35
38
 
36
39
  describe "Sphere function" do
37
40
  it 'can optimize the Sphere function in 3 dimensions' do
38
- best, obj = best_from_de_on_objective MinSphere.new, 3, 12_000
41
+ best, obj, time = best_from_de_on_objective MinSphere.new, 3, 12_000
42
+ best.must_be_close_to_one_solution_of obj
43
+ time.must_be :<, 1.5
44
+ end
45
+
46
+ it 'can optimize the Sphere function in 10 dimensions' do
47
+ best, obj, time = best_from_de_on_objective MinSphere.new, 10, 60_000
39
48
  best.must_be_close_to_one_solution_of obj
49
+ time.must_be :<, 7.5
40
50
  end
41
51
 
42
- # it 'can optimize the Sphere function in 10 dimensions' do
43
- # best, obj = best_from_de_on_objective MinSphere.new, 10, 60_000
44
- # best.must_be_close_to_one_solution_of obj
45
- # end
46
- #
47
- # it 'can optimize the Sphere function in 30 dimensions' do
48
- # best, obj = best_from_de_on_objective MinSphere.new, 30, 220_000
49
- # # We don't test closeness since it might take very long for 30D to get close on all dimensions.
50
- # end
52
+ it 'can optimize the Sphere function in 30 dimensions' do
53
+ best, obj, time = best_from_de_on_objective MinSphere.new, 30, 220_000
54
+ time.must_be :<, 28.0
55
+ # We don't test closeness since it might take very long for 30D to get close on all dimensions.
56
+ end
51
57
  end
52
58
 
53
59
  describe "Levi13 function" do
54
60
  it 'can optimize the Levi13 function' do
55
- objective = MinLevi13.new
56
- ss = objective.search_space
57
- de = DEOptimizer.new(objective, ss, {:verbose => false,
58
- :maxNumSteps => 7_500})
59
- best = de.optimize().to_a
60
-
61
- val = objective.calc_func(best)
62
- val.must_be_close_to objective.minimum
63
- val.must_be :>=, objective.minimum
64
-
65
- best.must_be_close_to_one_solution_of objective, 0.01
61
+ best, obj, time = best_from_de_on_objective MinLevi13.new, nil, 7_500
62
+ best.must_be_close_to_one_solution_of obj
63
+ time.must_be :<, 1.0
66
64
  end
67
65
  end
68
66
 
69
67
  describe "Beale function" do
70
68
  it 'can optimize the Beale function' do
71
- objective = MinBeale.new
72
- ss = objective.search_space
73
- de = DEOptimizer.new(objective, ss, {:verbose => false,
74
- :maxNumSteps => 7_500})
75
- best = de.optimize().to_a
76
-
77
- val = objective.calc_func(best)
78
- val.must_be_close_to objective.minimum
79
- val.must_be :>=, objective.minimum
80
-
81
- best.must_be_close_to_one_solution_of objective, 0.01
69
+ best, obj, time = best_from_de_on_objective MinBeale.new, nil, 7_500
70
+ best.must_be_close_to_one_solution_of obj
71
+ time.must_be :<, 1.0
82
72
  end
83
73
  end
84
74
 
@@ -88,7 +78,7 @@ describe "Easom function" do
88
78
  ss = objective.search_space
89
79
  # Why can't we do this in 25_000 evals anymore? We did it before. Repeatedly. Very strange.
90
80
  de = DEOptimizer.new(objective, ss, {:verbose => false,
91
- :maxNumSteps => 35_000, :printFrequency => 0.0,
81
+ :maxNumSteps => 40_000, :printFrequency => 0.0,
92
82
  :samplerRadius => 5})
93
83
  best = de.optimize().to_a
94
84
 
@@ -104,7 +94,7 @@ describe "EggHolder function" do
104
94
  it 'can optimize the Eggholder function' do
105
95
  objective = MinEggHolder.new
106
96
  ss = objective.search_space
107
- de = DEOptimizer.new(objective, ss, {:verbose => true,
97
+ de = DEOptimizer.new(objective, ss, {:verbose => false,
108
98
  :maxNumSteps => 25_000, :samplerRadius => 6})
109
99
  best = de.optimize().to_a
110
100
 
@@ -118,7 +108,8 @@ end
118
108
 
119
109
  describe "Schwefel 2.22 function" do
120
110
  it 'can optimize the Schwefel 2.22 function in 3 dimensions' do
121
- best, obj = best_from_de_on_objective MinSchwefel2_22.new, 3, 12_000
111
+ best, obj, time = best_from_de_on_objective MinSchwefel2_22.new, 3, 12_000
122
112
  best.must_be_close_to_one_solution_of obj
113
+ time.must_be :<, 1.5
123
114
  end
124
115
  end
@@ -16,7 +16,7 @@ end
16
16
 
17
17
  describe "EliteArchive" do
18
18
  before do
19
- @o = TwoMinOneMax.new
19
+ @o = TwoMinOneMax.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
20
20
  @a = FeldtRuby::Optimize::EliteArchive.new(@o, {
21
21
  :NumTopPerGoal => 2,
22
22
  :NumTopAggregate => 3})
@@ -12,7 +12,7 @@ end
12
12
 
13
13
  describe "a single minimizing objective" do
14
14
  before do
15
- @o = SingleObjective1.new
15
+ @o = SingleObjective1.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
16
16
  end
17
17
 
18
18
  it "has one goal" do
@@ -162,7 +162,7 @@ end
162
162
 
163
163
  describe "two sub-objectives" do
164
164
  before do
165
- @o = TwoMinObjectives1.new
165
+ @o = TwoMinObjectives1.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
166
166
  end
167
167
 
168
168
  it "has two aspects/sub-objectives" do
@@ -291,8 +291,8 @@ end
291
291
 
292
292
  describe "the objective itself and its updates" do
293
293
  before do
294
- @o = SingleObjective1.new
295
- @o2 = TwoMinObjectives1.new
294
+ @o = SingleObjective1.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
295
+ @o2 = TwoMinObjectives1.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
296
296
  @c = [1,2,3]
297
297
  end
298
298
 
@@ -383,7 +383,7 @@ end
383
383
 
384
384
  describe "calculating quality when there is one max goal" do
385
385
  before do
386
- @o = OneMinOneMaxObjective1.new
386
+ @o = OneMinOneMaxObjective1.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
387
387
  end
388
388
 
389
389
  it "inverts the max value so that it grows downwards" do
@@ -395,43 +395,86 @@ end
395
395
 
396
396
  describe "calculating quality with weights" do
397
397
  before do
398
- @o = OneMinOneMaxObjective1.new
398
+ @o = OneMinOneMaxObjective1.new(FeldtRuby::Optimize::Objective::WeightedSumAggregator.new)
399
399
  @o.weights = {:objective_min_distance_between => 2, :objective_max_sum => 3}
400
400
  end
401
401
 
402
- it "uses the weights when calculating quality" do
402
+ it "uses the weights when calculating quality, even after weights change" do
403
403
  i1 = [1,2,3]
404
- @o.weights = {:objective_min_distance_between => 2, :objective_max_sum => 3}
405
404
  q1 = @o.quality_of(i1)
406
- q1.value.must_equal( 2*((2-1) + (3-2)) + (-3)*(1+2+3) )
407
405
  q1.sub_qualities.must_equal [2.0, 6.0]
406
+ q1.value.must_equal( 2*((2-1) + (3-2)) + (-3)*(1+2+3) )
408
407
  q1.candidate.must_equal i1
409
408
  q1.objective.must_equal @o
410
409
 
411
410
  @o.weights = {:objective_min_distance_between => 5, :objective_max_sum => 30}
412
411
  q2 = @o.quality_of(i1)
413
- q2.value.must_equal( 5*((2-1) + (3-2)) + (-30)*(1+2+3) )
414
412
  q2.sub_qualities.must_equal [2.0, 6.0]
413
+ q2.value.must_equal( 5*((2-1) + (3-2)) + (-30)*(1+2+3) )
414
+
415
+ i2 = [1,2,5]
416
+ q3 = @o.quality_of i2
417
+ q3.sub_qualities.must_equal [4.0, 8.0]
418
+ q3.value.must_equal( 5*4.0 + (-30)*8.0 )
419
+
420
+ @o.weights = {:objective_min_distance_between => -10, :objective_max_sum => 1}
421
+ q3.value.must_equal( (-10)*4.0 + (-1)*8.0 )
422
+ q2.value.must_equal( (-10)*2.0 + (-1)*6.0 )
423
+ q1.value.must_equal( (-10)*2.0 + (-1)*6.0 )
424
+
425
+ @o.weights = {:objective_min_distance_between => -4, :objective_max_sum => -2}
426
+ q3.value.must_equal( (-4)*4.0 + (2)*8.0 ) # 0.0
427
+ q2.value.must_equal( (-4)*2.0 + (2)*6.0 ) # 4.0
428
+ q1.value.must_equal( (-4)*2.0 + (2)*6.0 )
429
+
430
+ i3 = [1,2,3,4,5,6]
431
+ q4 = @o.quality_of i3
432
+ q4.sub_qualities.must_equal [5.0, 21.0]
433
+ q4.value.must_equal( (-4)*5.0 + (2)*21.0 ) # 22.0
434
+
435
+ @o.rank_candidates([i1, i2, i3]).must_equal [i2, i1, i3]
436
+
437
+ @o.weights = {:objective_min_distance_between => 1, :objective_max_sum => 100}
438
+ @o.rank_candidates([i1, i2, i3]).must_equal [i3, i2, i1]
439
+
440
+ @o.weights = {:objective_min_distance_between => 100, :objective_max_sum => 1}
441
+ @o.rank_candidates([i1, i2, i3]).must_equal [i1, i2, i3]
415
442
  end
416
443
  end
417
444
 
418
445
  describe "Using MWGR for range-independent aggregate fitness calc" do
419
446
  before do
420
- @qa = FeldtRuby::Optimize::Objective::SumOfWeigthedGlobalRatios.new
447
+ @qa = FeldtRuby::Optimize::Objective::MeanWeigthedGlobalRatios.new
421
448
  @o = OneMinOneMaxObjective1.new(@qa)
422
449
  end
423
450
 
424
451
  it 'works for a simple scenario' do
425
- q1 = @o.quality_of([1,2]) # [1, 3] => 0.0
452
+ i1 = [1,2]
453
+ q1 = @o.quality_of(i1) # [1, 3] => 0.0
426
454
  q1.value.must_equal 0.0 # First eval must give perfect score since scales are tight...
427
455
 
428
- q2 = @o.quality_of([1,3]) # [2, 4] => 0.5
456
+ i2 = [1,3]
457
+ q2 = @o.quality_of(i2) # [2, 4] => 0.5
429
458
  q2.value.must_equal 0.5 # Perfect on one (max sum) and worst on other (min distance) so (0+1.0)/2
430
459
  q1.value.must_equal 0.5 # Perfect on one (min distance) and worst on other (max sum) so (1.0+0.0)/2
431
460
 
432
- q3 = @o.quality_of([1,4]) # [3, 5] => (0+1.0)/2
461
+ i3 = [1,4]
462
+ q3 = @o.quality_of(i3) # [3, 5] => (0+1.0)/2
433
463
  q3.value.must_equal 0.5 # Perfect on one (max sum) and worst on other (min distance) so (0+1.0)/2
434
464
  q2.value.must_equal( ((2.0-1.0)/(3.0-1.0) + ((5.0-4.0)/(5.0-3.0)))/2.0 )
435
465
  q1.value.must_equal( ((1.0-1.0)/(3.0-1.0) + ((5.0-3.0)/(5.0-3.0)))/2.0 )
466
+
467
+ i4 = [1,2,3]
468
+ q4 = @o.quality_of(i4) # [2, 6]
469
+ q4.value.must_equal( ((2.0-1.0)/(3.0-1.0) + ((6.0-6.0)/(6.0-3.0)))/2.0 )
470
+ q3.value.must_equal( ((3.0-1.0)/(3.0-1.0) + ((6.0-5.0)/(6.0-3.0)))/2.0 )
471
+ q2.value.must_equal( ((2.0-1.0)/(3.0-1.0) + ((6.0-4.0)/(6.0-3.0)))/2.0 )
472
+ q1.value.must_equal( ((1.0-1.0)/(3.0-1.0) + ((6.0-3.0)/(6.0-3.0)))/2.0 )
473
+
474
+ @o.rank_candidates([i1,i3,i4]).must_equal [i4,i1,i3]
475
+ @o.rank_candidates([i3,i4,i2]).must_equal [i4,i2,i3]
476
+ @o.rank_candidates([i3,i4]).must_equal [i4,i3]
477
+ @o.rank_candidates([i3,i1]).must_equal [i1,i3]
478
+ @o.rank_candidates([i2,i3]).must_equal [i2,i3]
436
479
  end
437
480
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feldtruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Feldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-06 00:00:00.000000000 Z
11
+ date: 2013-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rinruby