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.
- 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
@@ -0,0 +1,47 @@
|
|
1
|
+
$: << "../lib"
|
2
|
+
require 'feldtruby/mongodb_logger'
|
3
|
+
|
4
|
+
#l = FeldtRuby::MongoDBLogger.new
|
5
|
+
adbs = FeldtRuby::AllMongoDBLoggers.new "localhost", 27017
|
6
|
+
|
7
|
+
#adbs.delete_logger_dbs false
|
8
|
+
#exit -1
|
9
|
+
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
#pp adbs.all_log_infos
|
13
|
+
|
14
|
+
mc = Mongo::MongoClient.new "localhost", 27017
|
15
|
+
|
16
|
+
mc.database_names.each do |dbname|
|
17
|
+
|
18
|
+
db = mc.db(dbname)
|
19
|
+
|
20
|
+
cnames = db.collection_names
|
21
|
+
|
22
|
+
puts "db #{dbname} has #{cnames.length} collections: #{cnames.inspect}"
|
23
|
+
|
24
|
+
cnames.each do |cname|
|
25
|
+
|
26
|
+
next if cname == "system.indexes"
|
27
|
+
|
28
|
+
c = db[cname]
|
29
|
+
|
30
|
+
puts "#{dbname}/#{cname}:"
|
31
|
+
pp c.find.to_a
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
#pp l.mongo_client.database_names
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
#adbs.delete_all_logger_dbs_except_last_one
|
42
|
+
|
43
|
+
#pp adbs.all_log_infos
|
44
|
+
|
45
|
+
#l.log_value :a, 1
|
46
|
+
|
47
|
+
#pp l.mongo_client.database_names
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$: << "lib"
|
2
|
+
$: << "../lib"
|
3
|
+
require 'feldtruby/optimize/differential_evolution'
|
4
|
+
|
5
|
+
$NumSteps = (ARGV[0] && ARGV[0] =~ /^\d+/) ? ARGV[0].to_i : 10_000
|
6
|
+
$LC = ((ARGV[1] || ARGV[0]) == "EventLogger") ? FeldtRuby::EventLogger : FeldtRuby::Logger
|
7
|
+
|
8
|
+
class MinimizeRMS < FeldtRuby::Optimize::Objective
|
9
|
+
def objective_min_rms(candidate)
|
10
|
+
candidate.rms
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class MinimizeRMSAndSum < MinimizeRMS
|
15
|
+
def objective_min_sum(candidate)
|
16
|
+
candidate.sum.abs
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_default_logger
|
20
|
+
$LC.new(STDOUT)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
include FeldtRuby::Optimize
|
25
|
+
|
26
|
+
s4 = SearchSpace.new_symmetric(4, 1)
|
27
|
+
|
28
|
+
o2 = MinimizeRMSAndSum.new
|
29
|
+
|
30
|
+
de = DEOptimizer.new(o2, s4, {:verbose => true, :maxNumSteps => $NumSteps})
|
31
|
+
|
32
|
+
de.optimize()
|
data/test/helper.rb
CHANGED
@@ -4,5 +4,21 @@ require 'minitest/spec'
|
|
4
4
|
|
5
5
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
6
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
|
7
8
|
require 'feldtruby'
|
8
|
-
require 'feldtruby/minitest_extensions'
|
9
|
+
require 'feldtruby/minitest_extensions'
|
10
|
+
require 'feldtruby/optimize'
|
11
|
+
require 'feldtruby/optimize/objective'
|
12
|
+
|
13
|
+
# Common classes used in testing
|
14
|
+
class MinimizeRMS < FeldtRuby::Optimize::Objective
|
15
|
+
def objective_min_rms(candidate)
|
16
|
+
candidate.rms
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class MinimizeRMSAndSum < MinimizeRMS
|
21
|
+
def objective_min_sum(candidate)
|
22
|
+
candidate.sum.abs
|
23
|
+
end
|
24
|
+
end
|
@@ -136,7 +136,11 @@ describe "Basic statistics" do
|
|
136
136
|
|
137
137
|
describe "summary_stats" do
|
138
138
|
it "gives a nice string with descriptive statistics" do
|
139
|
-
[1,2,3,4].summary_stats.must_equal "2.
|
139
|
+
[1,2,3,4].summary_stats.must_equal "2.5 (min = 1, max = 4, median = 2.5, stdev = 1.12)"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "returns an empty string if there are no values" do
|
143
|
+
[].summary_stats.must_equal ""
|
140
144
|
end
|
141
145
|
end
|
142
146
|
|
@@ -40,4 +40,27 @@ describe "all pairs of elements from an array" do
|
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'all combinations of elements from sub-arrays' do
|
46
|
+
it 'returns an empty array if no sub-arrays given' do
|
47
|
+
[].all_combinations_one_from_each.must_equal []
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'can handle the case with only one sub-array' do
|
51
|
+
[[1]].all_combinations_one_from_each.must_equal [[1]]
|
52
|
+
[[1, 2]].all_combinations_one_from_each.must_equal [[1], [2]]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can handle a simple, basic example' do
|
56
|
+
[[1,2], [3]].all_combinations_one_from_each.must_equal [[1,3], [2,3]]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can handle the case of two sub-arrays of two elements each' do
|
60
|
+
[[1,2], [3,7]].all_combinations_one_from_each.must_equal [[1,3], [2,3], [1,7], [2,7]]
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'can handle the case of two sub-arrays of two and three elements, respectively' do
|
64
|
+
[[1,2,3], [4,5]].all_combinations_one_from_each.must_equal [[1,4], [2,4], [3,4], [1,5], [2,5], [3,5]]
|
65
|
+
end
|
43
66
|
end
|
data/test/test_float.rb
CHANGED
@@ -17,4 +17,19 @@ describe "protected_division_with" do
|
|
17
17
|
it "returns positive infinity if numerator is positive and denominator is zero" do
|
18
18
|
1.0.protected_division_with(0).must_equal 0.0
|
19
19
|
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'to_significant_digits' do
|
23
|
+
it 'can handle normal, floats around zero' do
|
24
|
+
1.0.to_significant_digits(2).must_equal 1.0
|
25
|
+
1.11.to_significant_digits(2).must_equal 1.1
|
26
|
+
2.345.to_significant_digits(3).must_equal 2.35
|
27
|
+
2.345.to_significant_digits(4).must_equal 2.345
|
28
|
+
(-9.8654).to_significant_digits(3).must_equal -9.87
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can handle Infinity' do
|
32
|
+
Float::INFINITY.to_significant_digits(2).must_equal Float::INFINITY
|
33
|
+
(-Float::INFINITY).to_significant_digits(2).must_equal (-Float::INFINITY)
|
34
|
+
end
|
20
35
|
end
|
@@ -16,7 +16,7 @@ def quicker_has_network_connection?
|
|
16
16
|
reply != "" # Is empty if no connection since error is printed on STDERR
|
17
17
|
end
|
18
18
|
|
19
|
-
if quicker_has_network_connection?
|
19
|
+
if false # quicker_has_network_connection? # Hangs quite often, skip for now...
|
20
20
|
|
21
21
|
describe "HtmlDocGetter" do
|
22
22
|
it "Can get the html page as a string" do
|
data/test/test_logger.rb
CHANGED
@@ -1,96 +1,134 @@
|
|
1
1
|
require 'feldtruby/logger'
|
2
|
+
require 'stringio'
|
2
3
|
|
3
4
|
describe 'Logger' do
|
4
5
|
|
5
6
|
before do
|
6
7
|
@sio = StringIO.new
|
7
|
-
@l = FeldtRuby::Logger.new @sio
|
8
|
+
@l = FeldtRuby::Logger.new @sio, {:verbose => true,
|
9
|
+
:print_frequency => 0.0 # So everything is logged
|
10
|
+
}
|
8
11
|
end
|
9
12
|
|
10
13
|
it 'has a event count of 0 when no events has been logged' do
|
11
|
-
|
12
14
|
@l.num_events.must_equal 0
|
13
|
-
|
14
15
|
end
|
15
16
|
|
16
|
-
it '
|
17
|
+
it 'can log counter events' do
|
17
18
|
|
18
|
-
@l.
|
19
|
-
@l.num_events.must_equal 1
|
19
|
+
@l.num_events(:a).must_equal 0
|
20
20
|
|
21
|
-
@l.
|
22
|
-
@l.num_events.must_equal
|
21
|
+
@l.log_counter :a
|
22
|
+
@l.num_events(:a).must_equal 1
|
23
23
|
|
24
|
+
@l.log_counter :a
|
25
|
+
@l.num_events(:a).must_equal 2
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'logs value events' do
|
30
|
+
@l.log_value :v, 1, "a = 1"
|
31
|
+
@l.num_events(:v).must_equal 1
|
32
|
+
@sio.string.split("\n").last[-5..-1].must_equal "a = 1"
|
33
|
+
|
34
|
+
@l.log_value :v, 2, "a"
|
35
|
+
@l.num_events(:v).must_equal 2
|
36
|
+
@sio.string.split("\n").last[-1..-1].must_equal "a"
|
24
37
|
end
|
25
38
|
|
26
39
|
it 'can log default events (described in strings)' do
|
27
40
|
|
28
41
|
@l.log "event 1"
|
29
|
-
@sio.string.must_equal "event 1
|
42
|
+
@sio.string.split("\n").last[-7..-1].must_equal "event 1"
|
30
43
|
@l.num_events.must_equal 1
|
31
44
|
|
32
45
|
@l.log "event 2"
|
33
|
-
@sio.string.must_equal "event
|
46
|
+
@sio.string.split("\n").last[-7..-1].must_equal "event 2"
|
34
47
|
@l.num_events.must_equal 2
|
35
48
|
|
36
49
|
end
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
@l.log "1", :increase
|
41
|
-
@sio.string.must_equal "{increase}: 1\n"
|
42
|
-
@l.num_events.must_equal 0
|
43
|
-
@l.num_events(:increase).must_equal 1
|
51
|
+
end
|
44
52
|
|
45
|
-
|
46
|
-
@sio.string.must_equal "{increase}: 1\n{increase}: 2\n"
|
47
|
-
@l.num_events.must_equal 0
|
48
|
-
@l.num_events(:increase).must_equal 2
|
53
|
+
describe 'Logger with a non-zero print frequency' do
|
49
54
|
|
55
|
+
before do
|
56
|
+
@sio = StringIO.new
|
57
|
+
@l = FeldtRuby::Logger.new @sio, {:verbose => true,
|
58
|
+
:print_frequency => 0.1
|
59
|
+
}
|
50
60
|
end
|
51
61
|
|
52
|
-
it '
|
62
|
+
it 'only logs if log event comes less often than the print frequency' do
|
53
63
|
|
54
|
-
@l.
|
55
|
-
@l.
|
64
|
+
@l.log_value :v, 1, "a = 1"
|
65
|
+
@l.num_events(:v).must_equal 1
|
56
66
|
|
57
|
-
|
58
|
-
@l.
|
67
|
+
# This event comes right after so is only counted, not printed
|
68
|
+
@l.log_value :v, 2, "a = 2"
|
69
|
+
@l.num_events(:v).must_equal 2
|
70
|
+
@sio.string.split("\n").last[-5..-1].must_equal "a = 1"
|
59
71
|
|
60
|
-
|
72
|
+
# Ensure we have waited longer than print frequency
|
73
|
+
sleep 0.1
|
74
|
+
@l.log_value :v, 3, "a = 3"
|
75
|
+
@l.num_events(:v).must_equal 3
|
76
|
+
@sio.string.split("\n").last[-5..-1].must_equal "a = 3"
|
61
77
|
|
62
|
-
|
78
|
+
end
|
63
79
|
|
64
|
-
|
65
|
-
@l.log "2", :increase
|
66
|
-
@l.log "0.4", :alpha
|
67
|
-
@l.log "1", :increase
|
80
|
+
it 'always logs the default events' do
|
68
81
|
|
69
|
-
@l.
|
82
|
+
@l.log "1"
|
83
|
+
@sio.string.split("\n").last[-1..-1].must_equal "1"
|
70
84
|
|
71
|
-
@l.
|
85
|
+
@l.log "2"
|
86
|
+
@sio.string.split("\n").last[-1..-1].must_equal "2"
|
72
87
|
|
73
|
-
|
88
|
+
sleep 0.1
|
89
|
+
@l.log "3"
|
90
|
+
@sio.string.split("\n").last[-1..-1].must_equal "3"
|
74
91
|
|
75
92
|
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'Logger with two IO output streams' do
|
96
|
+
it 'logs to all streams of more than one' do
|
97
|
+
sio1 = StringIO.new
|
98
|
+
l = FeldtRuby::Logger.new sio1, {:verbose => true,
|
99
|
+
:print_frequency => 0.0
|
100
|
+
}
|
101
|
+
sio2 = StringIO.new
|
102
|
+
l.add_io sio2
|
103
|
+
|
104
|
+
l.log "event 1"
|
105
|
+
l.num_events.must_equal 1
|
106
|
+
sio1.string.split("\n").last[-7..-1].must_equal "event 1"
|
107
|
+
sio2.string.split("\n").last[-7..-1].must_equal "event 1"
|
108
|
+
|
109
|
+
sio3 = StringIO.new
|
110
|
+
l.add_io sio3
|
111
|
+
l.log "event 2"
|
112
|
+
l.num_events.must_equal 2
|
113
|
+
sio1.string.split("\n").last[-7..-1].must_equal "event 2"
|
114
|
+
sio2.string.split("\n").last[-7..-1].must_equal "event 2"
|
115
|
+
sio3.string.split("\n").last[-7..-1].must_equal "event 2"
|
116
|
+
end
|
76
117
|
|
77
|
-
it '
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
118
|
+
it 'can add filenames to which log output should be written' do
|
119
|
+
sio1 = StringIO.new
|
120
|
+
l = FeldtRuby::Logger.new sio1, {:verbose => true,
|
121
|
+
:print_frequency => 0.0
|
122
|
+
}
|
82
123
|
|
83
|
-
|
84
|
-
time_stamps_b = @l.events(:b).map {|e| e.time_stamp}
|
124
|
+
filename = "temp390580943850834.log"
|
85
125
|
|
86
|
-
|
87
|
-
|
88
|
-
time_stamps_b[0].must_be_instance_of Time
|
126
|
+
File.delete filename if File.exist?(filename)
|
127
|
+
l.add_output_file filename
|
89
128
|
|
90
|
-
|
91
|
-
|
92
|
-
|
129
|
+
l.log "event 1"
|
130
|
+
File.exist?(filename).must_equal true
|
131
|
+
File.delete filename
|
93
132
|
|
94
133
|
end
|
95
|
-
|
96
134
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'feldtruby/mongodb_logger'
|
2
|
+
|
3
|
+
if FeldtRuby.is_mongo_running?
|
4
|
+
|
5
|
+
describe 'AllMongoDBLoggers' do
|
6
|
+
before do
|
7
|
+
@adbs = FeldtRuby::AllMongoDBLoggers.new "localhost", 27017
|
8
|
+
@l = FeldtRuby::MongoDBLogger.new
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
@adbs.drop_db_named @l.db_name
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can list all logs in the db, and there is at least one with the right name since we created one' do
|
16
|
+
|
17
|
+
alis = @adbs.all_log_infos
|
18
|
+
alis.must_be_instance_of Array
|
19
|
+
|
20
|
+
dbn = alis.first["db_name"]
|
21
|
+
dbn.must_match /MongoDBLogger_\d{8}_\d{6}_\d+/
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'MongoDBLogger' do
|
28
|
+
|
29
|
+
before do
|
30
|
+
@sio = StringIO.new
|
31
|
+
@l = FeldtRuby::MongoDBLogger.new @sio, {:verbose => true}
|
32
|
+
@adbs = FeldtRuby::AllMongoDBLoggers.new "localhost", 27017
|
33
|
+
end
|
34
|
+
|
35
|
+
after do
|
36
|
+
@adbs.drop_db_named @l.db_name
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can log counter events' do
|
40
|
+
@l.num_events(:a).must_equal 0
|
41
|
+
@l.log_counter :a
|
42
|
+
@l.num_events(:a).must_equal 1
|
43
|
+
@l.log_counter :a
|
44
|
+
@l.num_events(:a).must_equal 2
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'can log value events where the values are numbers' do
|
48
|
+
|
49
|
+
@l.log_value :a, 2
|
50
|
+
c = @l.collection_for_type :a
|
51
|
+
c.find.to_a.length.must_equal 1
|
52
|
+
|
53
|
+
@l.log_value :a, 3
|
54
|
+
c.find.to_a.length.must_equal 2
|
55
|
+
|
56
|
+
@l.current_value(:a).must_equal 3
|
57
|
+
@l.previous_value(:a).must_equal 2
|
58
|
+
|
59
|
+
@l.log_value :a, 4
|
60
|
+
c.find.to_a.length.must_equal 3
|
61
|
+
|
62
|
+
@l.log_value :b, -100
|
63
|
+
cb = @l.collection_for_type :b
|
64
|
+
cb.find.to_a.length.must_equal 1
|
65
|
+
|
66
|
+
@l.current_value(:a).must_equal 4
|
67
|
+
@l.previous_value(:a).must_equal 3
|
68
|
+
|
69
|
+
@l.current_value(:b).must_equal -100
|
70
|
+
|
71
|
+
es = @l.events(:a)
|
72
|
+
|
73
|
+
es.length.must_equal 3
|
74
|
+
|
75
|
+
es[0].keys.sort.must_equal ["_id", "t", "v"].sort
|
76
|
+
es[1].keys.sort.must_equal ["_id", "t", "v"].sort
|
77
|
+
es[2].keys.sort.must_equal ["_id", "t", "v"].sort
|
78
|
+
|
79
|
+
es[0]["t"].micro_seconds.must_be :<=, es[1]["t"].micro_seconds
|
80
|
+
es[1]["t"].micro_seconds.must_be :<=, es[2]["t"].micro_seconds
|
81
|
+
|
82
|
+
es[0]["v"].must_equal 2
|
83
|
+
es[1]["v"].must_equal 3
|
84
|
+
es[2]["v"].must_equal 4
|
85
|
+
|
86
|
+
@l.num_events(:a).must_equal 3
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'can log data events' do
|
91
|
+
|
92
|
+
@l.log_data :bg, {:a => 1, :b => 2}
|
93
|
+
c = @l.collection_for_type :bg
|
94
|
+
|
95
|
+
c.find.to_a.length.must_equal 1
|
96
|
+
|
97
|
+
@l.log_data :bg, {:a => 3, :b => 4}
|
98
|
+
|
99
|
+
es = c.find.to_a
|
100
|
+
|
101
|
+
es.length.must_equal 2
|
102
|
+
|
103
|
+
es[0]["d"]["a"].must_equal 1
|
104
|
+
es[0]["d"]["b"].must_equal 2
|
105
|
+
|
106
|
+
es[1]["d"]["a"].must_equal 3
|
107
|
+
es[1]["d"]["b"].must_equal 4
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
else
|
113
|
+
|
114
|
+
puts "!!!!! NOTE !!!!!\n Not testing MongoDBLogger since mongod is not running. Start with:\n mongod\n!!!!!"
|
115
|
+
|
116
|
+
end
|
data/test/test_optimize.rb
CHANGED
@@ -2,20 +2,21 @@ require 'feldtruby/optimize'
|
|
2
2
|
|
3
3
|
class TestOptimize < MiniTest::Unit::TestCase
|
4
4
|
def test_rosenbrock_optimization_as_in_README
|
5
|
-
xbest, ybest = FeldtRuby::Optimize.optimize(0, 2, {:
|
5
|
+
xbest, ybest = FeldtRuby::Optimize.optimize(0, 2, {:maxNumSteps => 10_000,
|
6
|
+
:verbose => false}) {|x, y|
|
6
7
|
(1 - x)**2 + 100*(y - x*x)**2
|
7
8
|
}
|
8
|
-
assert_in_delta 1.0, xbest
|
9
|
-
assert_in_delta 1.0, ybest
|
9
|
+
assert_in_delta 1.0, xbest, 0.005
|
10
|
+
assert_in_delta 1.0, ybest, 0.005
|
10
11
|
end
|
11
12
|
|
12
|
-
def in_vicinity?(x, y, delta = 0.
|
13
|
+
def in_vicinity?(x, y, delta = 0.1)
|
13
14
|
(x-y).abs < delta
|
14
15
|
end
|
15
16
|
|
16
17
|
def test_himmelsblau_minimization
|
17
18
|
# For details see: http://en.wikipedia.org/wiki/Himmelblau%27s_function
|
18
|
-
xbest, ybest = FeldtRuby::Optimize.minimize(-5, 5, {:maxNumSteps =>
|
19
|
+
xbest, ybest = FeldtRuby::Optimize.minimize(-5, 5, {:maxNumSteps => 6_000, :verbose => false}) {|x, y|
|
19
20
|
(x*x + y - 11)**2 + (x + y*y + - 7)**2
|
20
21
|
}
|
21
22
|
|
@@ -46,7 +47,7 @@ class TestOptimize < MiniTest::Unit::TestCase
|
|
46
47
|
def test_himmelsblau_maximization
|
47
48
|
# There is a local maxima that can be found if we search in a smaller box around 0.0.
|
48
49
|
# For details see: http://en.wikipedia.org/wiki/Himmelblau%27s_function
|
49
|
-
xbest, ybest = FeldtRuby::Optimize.maximize(-1, 1, {:maxNumSteps =>
|
50
|
+
xbest, ybest = FeldtRuby::Optimize.maximize(-1, 1, {:maxNumSteps => 3_000, :verbose => false}) {|x, y|
|
50
51
|
(x*x + y - 11)**2 + (x + y*y + - 7)**2
|
51
52
|
}
|
52
53
|
assert_in_delta -0.270845, xbest, 0.1
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'feldtruby/optimize/differential_evolution'
|
2
2
|
require 'feldtruby/array/basic_stats'
|
3
|
+
include FeldtRuby::Optimize
|
3
4
|
|
4
5
|
class MinimizeRMS < FeldtRuby::Optimize::Objective
|
5
6
|
def objective_min_rms(candidate)
|
@@ -13,30 +14,31 @@ class MinimizeRMSAndSum < MinimizeRMS
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@o1 = MinimizeRMS.new
|
23
|
-
@o2 = MinimizeRMSAndSum.new
|
24
|
-
|
25
|
-
@de1 = DEOptimizer.new(@o1, @s2, {:verbose => false, :maxNumSteps => 1000})
|
26
|
-
@de2 = DEOptimizer.new(@o2, @s4, {:verbose => false, :maxNumSteps => 1234})
|
17
|
+
describe "DifferentialEvolution" do
|
18
|
+
it 'has the same logger set on itself and all sub-classes' do
|
19
|
+
s2 = SearchSpace.new_symmetric(2, 1)
|
20
|
+
o1 = MinimizeRMS.new
|
21
|
+
de1 = DEOptimizer.new(o1, s2, {:verbose => false, :maxNumSteps => 1000})
|
22
|
+
de1.logger.must_equal o1.logger
|
27
23
|
end
|
28
24
|
|
29
|
-
|
30
|
-
|
25
|
+
it "works for rms of small vector" do
|
26
|
+
s2 = SearchSpace.new_symmetric(2, 1)
|
27
|
+
o1 = MinimizeRMS.new
|
28
|
+
de1 = DEOptimizer.new(o1, s2, {:verbose => false, :maxNumSteps => 1000})
|
29
|
+
de1.optimize()
|
31
30
|
# Very unlikely we get a number over 0.30 (2 elements) after 1000 steps...
|
32
|
-
|
33
|
-
|
31
|
+
de1.best.sum.must_be :<=, 0.30
|
32
|
+
de1.num_optimization_steps.must_equal 1000
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
|
35
|
+
it "works for rms and sum of small vector and with more steps" do
|
36
|
+
s4 = SearchSpace.new_symmetric(4, 1)
|
37
|
+
o2 = MinimizeRMSAndSum.new
|
38
|
+
de2 = DEOptimizer.new(o2, s4, {:verbose => false, :maxNumSteps => 1234})
|
39
|
+
de2.optimize()
|
38
40
|
# Very unlikely we get a number over 0.40 (4 elements)...
|
39
|
-
|
40
|
-
|
41
|
+
de2.best.sum.must_be :<=, 0.40
|
42
|
+
de2.num_optimization_steps.must_equal 1234
|
41
43
|
end
|
42
44
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'feldtruby/optimize/elite_archive'
|
2
|
+
|
3
|
+
class TwoMinOneMax < FeldtRuby::Optimize::Objective
|
4
|
+
def objective_min_1(x)
|
5
|
+
x.sum
|
6
|
+
end
|
7
|
+
|
8
|
+
def objective_min_2(x)
|
9
|
+
x.max
|
10
|
+
end
|
11
|
+
|
12
|
+
def objective_max_1(x)
|
13
|
+
x.min
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "EliteArchive" do
|
18
|
+
before do
|
19
|
+
@o = TwoMinOneMax.new
|
20
|
+
@a = FeldtRuby::Optimize::EliteArchive.new(@o, {
|
21
|
+
:NumTopPerGoal => 2,
|
22
|
+
:NumTopAggregate => 3})
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is adapted to an objective when created' do
|
26
|
+
@a.objective.must_equal @o
|
27
|
+
@a.top_per_goal.length.must_equal @o.num_goals
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'properly handles additions' do
|
31
|
+
i1 = [1,2,3]
|
32
|
+
@a.add i1 # [6, 3, 1] => 8
|
33
|
+
@a.best.length.must_equal 1
|
34
|
+
@a.top_per_goal[0].length.must_equal 1
|
35
|
+
@a.top_per_goal[1].length.must_equal 1
|
36
|
+
@a.top_per_goal[2].length.must_equal 1
|
37
|
+
|
38
|
+
i2 = [1,2,4]
|
39
|
+
@a.add i2 # [7, 4, 1] => 10
|
40
|
+
@a.best.length.must_equal 2
|
41
|
+
@a.top_per_goal[0].length.must_equal 2
|
42
|
+
@a.top_per_goal[1].length.must_equal 2
|
43
|
+
@a.top_per_goal[2].length.must_equal 2
|
44
|
+
@a.top_per_goal[0][0].must_equal i1
|
45
|
+
@a.top_per_goal[0][1].must_equal i2
|
46
|
+
@a.top_per_goal[1][0].must_equal i1
|
47
|
+
@a.top_per_goal[1][1].must_equal i2
|
48
|
+
|
49
|
+
i3 = [1,2,0] # [3, 2, 0] => 5
|
50
|
+
@a.add i3
|
51
|
+
|
52
|
+
@a.best.length.must_equal 3
|
53
|
+
@a.top_per_goal[0].length.must_equal 2
|
54
|
+
@a.top_per_goal[1].length.must_equal 2
|
55
|
+
@a.top_per_goal[2].length.must_equal 2
|
56
|
+
|
57
|
+
@a.best[0].must_equal i3
|
58
|
+
@a.best[1].must_equal i1
|
59
|
+
@a.best[2].must_equal i2
|
60
|
+
|
61
|
+
@a.top_per_goal[0][0].must_equal i3
|
62
|
+
@a.top_per_goal[0][1].must_equal i1
|
63
|
+
|
64
|
+
@a.top_per_goal[1][0].must_equal i3
|
65
|
+
@a.top_per_goal[1][1].must_equal i1
|
66
|
+
|
67
|
+
@a.top_per_goal[2][0].must_equal i1
|
68
|
+
@a.top_per_goal[2][1].must_equal i2
|
69
|
+
|
70
|
+
i4 = [5,5,10] # [20, 10, 5] => 25
|
71
|
+
@a.add i4
|
72
|
+
|
73
|
+
@a.best.length.must_equal 3
|
74
|
+
@a.top_per_goal[0].length.must_equal 2
|
75
|
+
@a.top_per_goal[1].length.must_equal 2
|
76
|
+
@a.top_per_goal[2].length.must_equal 2
|
77
|
+
|
78
|
+
@a.best[0].must_equal i3
|
79
|
+
@a.best[1].must_equal i1
|
80
|
+
@a.best[2].must_equal i2
|
81
|
+
|
82
|
+
@a.top_per_goal[2][0].must_equal i4
|
83
|
+
@a.top_per_goal[2][1].must_equal i1
|
84
|
+
end
|
85
|
+
end
|