answer-factory 0.1.2 → 0.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/answer-factory.gemspec +15 -8
- data/lib/answer-factory.rb +2 -0
- data/lib/factories/factory.rb +7 -0
- data/lib/factories/workstation.rb +16 -0
- data/lib/machines/evaluate_with_test_cases.rb +140 -0
- data/lib/machines/infrastructure.rb +2 -0
- data/lib/machines/select_by_summed_rank.rb +54 -0
- data/spec/factories/factory_spec.rb +13 -1
- data/spec/factories/workstation_spec.rb +19 -0
- data/spec/fixtures/my_data_source.csv +4 -0
- data/spec/integration_specs/couch_db_integration.rspec +59 -1
- data/spec/machines/evaluate_with_test_cases_spec.rb +296 -0
- data/spec/machines/select_by_summed_rank_spec.rb +134 -0
- data/spec/machines/select_nondominated_spec.rb +8 -0
- data/spec/spec_helper.rb +2 -1
- data/templates/answer_factory_activate_template.erb +44 -56
- metadata +33 -5
@@ -0,0 +1,296 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
include Machines
|
3
|
+
|
4
|
+
FakeWeb.allow_net_connect = false
|
5
|
+
|
6
|
+
|
7
|
+
describe "Machines::TestCase" do
|
8
|
+
describe "inputs Array" do
|
9
|
+
before(:each) do
|
10
|
+
@tc = TestCase.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "bindings" do
|
14
|
+
it "should have an attribute called #inputs" do
|
15
|
+
@tc.should respond_to(:inputs)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should accept a Hash as an initialization argument for #inputs" do
|
19
|
+
lambda{TestCase.new(inputs:{})}.should_not raise_error
|
20
|
+
TestCase.new(inputs:{"x1" => [:int, 12]}).inputs.should ==
|
21
|
+
{"x1" => [:int, 12]}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should default :inputs to an empty Hash" do
|
25
|
+
TestCase.new.inputs.should == {}
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have an attribute called #outputs" do
|
29
|
+
@tc.should respond_to(:outputs)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should accept a Hash as an initialization argument for #outputs" do
|
33
|
+
lambda{TestCase.new(outputs:{})}.should_not raise_error
|
34
|
+
TestCase.new(outputs:{"y1" => [:bool, false]}).outputs.should ==
|
35
|
+
{"y1" => [:bool, false]}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should default :inputs to an empty Hash" do
|
39
|
+
TestCase.new.outputs.should == {}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
describe "EvaluateWithTestCases" do
|
47
|
+
|
48
|
+
before(:each) do
|
49
|
+
@canned = '{"total_rows":1,"offset":0,"rows":[{"id":"0f60c293ad736abfdb083d33f71ef9ab","key":"ws1","value":{"_id":"0f60c293ad736abfdb083d33f71ef9ab","_rev":"1-473467b6dc1a4cba3498dd6eeb8e3206","blueprint":"do bar","tags":[],"scores":{},"progress":12,"timestamp":"2010/04/14 17:09:14 +0000"}}]}'
|
50
|
+
|
51
|
+
FakeWeb.register_uri(:any, "http://127.0.0.1:5984/foo_training/_design/tester/_view/test_cases",
|
52
|
+
:body => @canned, :status => [200, "OK"])
|
53
|
+
@factory = Factory.new(name:"foo")
|
54
|
+
@tester = EvaluateWithTestCases.new(name: :tester)
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "initialization" do
|
58
|
+
|
59
|
+
describe "name" do
|
60
|
+
it "should have a name" do
|
61
|
+
@tester.should respond_to(:name)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "data" do
|
66
|
+
it "should call #load_training_data! if" do
|
67
|
+
EvaluateWithTestCases.new(name: :tester)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "sensors" do
|
72
|
+
it "should have a #sensors attribute" do
|
73
|
+
EvaluateWithTestCases.new(name: :tester).should respond_to(:sensors)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should default to an empty Hash" do
|
77
|
+
EvaluateWithTestCases.new(name: :tester).sensors.should == {}
|
78
|
+
end
|
79
|
+
|
80
|
+
describe ":build_sensor" do
|
81
|
+
before(:each) do
|
82
|
+
@m1 = EvaluateWithTestCases.new(name: :tester)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should respond to :build_sensor" do
|
86
|
+
@m1.should respond_to(:build_sensor)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should use the name argument as the Hash key in #sensors" do
|
90
|
+
@m1.build_sensor("harbor_master_score")
|
91
|
+
@m1.sensors.keys.should include("harbor_master_score")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should take a block and store it as a Proc as the value in #sensors" do
|
95
|
+
block = lambda {|a| 9}
|
96
|
+
@m1.build_sensor("harbor_master_score", &block)
|
97
|
+
@m1.sensors["harbor_master_score"].should == block
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
describe "#score method" do
|
106
|
+
it "should respond to :score" do
|
107
|
+
@tester.should respond_to(:score)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should only accept a Batch" do
|
111
|
+
lambda{@tester.score(99)}.should raise_error(ArgumentError)
|
112
|
+
lambda{@tester.score(Batch.new)}.should_not raise_error(ArgumentError)
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "running Interpreter" do
|
116
|
+
before(:each) do
|
117
|
+
@tester.test_cases = [TestCase.new(inputs: {"x1:int" => 1}, outputs: {"y1" => 2})]
|
118
|
+
@batch = Batch.[](Answer.new("do a"))
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should create one Interpreter for each TestCase of #data_in_hand" do
|
122
|
+
i = Interpreter.new("")
|
123
|
+
Interpreter.should_receive(:new).at_least(1).times.and_return(i)
|
124
|
+
@tester.score(@batch)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should register all the sensors" do
|
128
|
+
@tester.sensors = {"y1" => Proc.new{|interpreter| interpreter.peek_value(:int)} }
|
129
|
+
i = Interpreter.new
|
130
|
+
Interpreter.should_receive(:new).and_return(i)
|
131
|
+
i.should_receive(:register_sensor).exactly(1).times
|
132
|
+
@tester.score(@batch)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should set up Interpreters correctly" do
|
136
|
+
i = Interpreter.new
|
137
|
+
Interpreter.should_receive(:new).with(
|
138
|
+
"do a", {:name=>:tester, :target_size_in_points=>99}).and_return(i)
|
139
|
+
@tester.score(@batch,target_size_in_points:99)
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "install_training_data_from_csv!" do
|
147
|
+
before(:each) do
|
148
|
+
FakeWeb.register_uri(:any,
|
149
|
+
"http://127.0.0.1:5984/dammit_training/_bulk_docs",
|
150
|
+
:body => @canned, :status => [200, "OK"])
|
151
|
+
FakeWeb.register_uri(:any,
|
152
|
+
"http://127.0.0.1:5984/dammit_training/_design/tester/_view/test_cases",
|
153
|
+
:body => @canned, :status => [200, "OK"])
|
154
|
+
|
155
|
+
@f1 = Factory.new(name: "dammit")
|
156
|
+
@my_csv = "./spec/fixtures/my_data_source.csv"
|
157
|
+
@m1 = EvaluateWithTestCases.new(name: :tester, training_data_csv: @my_csv)
|
158
|
+
@training_db = "http://127.0.0.1:5984/dammit_training"
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should get the filename as an initialization parameter" do
|
163
|
+
EvaluateWithTestCases.new(name: :tester, training_data_csv: "foo.csv").
|
164
|
+
csv_filename.should == "foo.csv"
|
165
|
+
EvaluateWithTestCases.new(name: :tester).csv_filename.should == nil
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should open a csv file" do
|
169
|
+
f = File.open(@my_csv)
|
170
|
+
File.should_receive(:open).and_return(f)
|
171
|
+
c = CSV.new(f, headers: true)
|
172
|
+
CSV.should_receive(:new).with(f, headers: true).and_return(c)
|
173
|
+
@m1.install_training_data_from_csv(@my_csv)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should be the training_data default db" do
|
177
|
+
db = CouchRest.database!(@training_db)
|
178
|
+
CouchRest.should_receive(:database!).with(@training_db).and_return(db)
|
179
|
+
@m1.install_training_data_from_csv(@my_csv)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "makes one doc for every row" do
|
183
|
+
db = CouchRest.database!(@training_db)
|
184
|
+
CouchRest.should_receive(:database!).with(@training_db).and_return(db)
|
185
|
+
db.should_receive(:bulk_save_doc).exactly(3).times
|
186
|
+
@m1.install_training_data_from_csv(@my_csv)
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
it "should raise an error if every header doesn't contain a colon and a type string" do
|
191
|
+
lambda{@m1.header_prep("x1")}.should raise_error ArgumentError
|
192
|
+
lambda{@m1.header_prep("x1:")}.should raise_error ArgumentError
|
193
|
+
lambda{@m1.header_prep("x1:int")}.should_not raise_error ArgumentError
|
194
|
+
lambda{@m1.header_prep(":int")}.should raise_error ArgumentError
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "load_training_data!" do
|
200
|
+
|
201
|
+
before(:each) do
|
202
|
+
@factoreee = Factory.new(name:"dammit")
|
203
|
+
@m1 = EvaluateWithTestCases.new(name: :tester)
|
204
|
+
@design_doc = "tester/test_cases" # we'll assume this has been set up!
|
205
|
+
@expected = {"total_rows"=>1, "offset"=>0, "rows"=>[{"id"=>"05d195b7bb436743ee36b4223008c4ce", "key"=>"05d195b7bb436743ee36b4223008c4ce", "value"=>{"_id"=>"05d195b7bb436743ee36b4223008c4ce", "_rev"=>"1-c9fae927001a1d4789d6396bcf0cd5a7", "inputs"=>{"x1:int"=>7}, "outputs"=>{"y1:grault"=>12}}}]}
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should get the couch_db uri from configatron" do
|
210
|
+
@m1.training_data_view.should ==
|
211
|
+
"http://127.0.0.1:5984/dammit_training/_design/#{@m1.name}/_view/test_cases"
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should respond to :load_training_data!" do
|
215
|
+
@m1.should respond_to(:load_training_data!)
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should access the couch_db uri" do
|
219
|
+
FakeWeb.register_uri(:any,
|
220
|
+
"http://127.0.0.1:5984/dammit_training/_design/tester/_view/test_cases",
|
221
|
+
:body => @canned, :status => [200, "OK"])
|
222
|
+
db = CouchRest.database!(@m1.training_datasource)
|
223
|
+
CouchRest.should_receive(:database!).and_return(db)
|
224
|
+
db.should_receive(:view).with(@design_doc).and_return(@expected)
|
225
|
+
@m1.load_training_data!
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should throw a useful error if the view isn't available"
|
229
|
+
|
230
|
+
it "should ask for the view document" do
|
231
|
+
db = CouchRest.database!(@m1.training_datasource)
|
232
|
+
CouchRest.should_receive(:database!).and_return(db)
|
233
|
+
db.should_receive(:view).with(@design_doc).and_return(@expected)
|
234
|
+
@m1.load_training_data!
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should store Array of TestCases in @test_cases" do
|
238
|
+
db = CouchRest.database!(@m1.training_datasource)
|
239
|
+
CouchRest.should_receive(:database!).and_return(db)
|
240
|
+
db.should_receive(:view).with(@design_doc).and_return(@expected)
|
241
|
+
|
242
|
+
@m1.load_training_data!
|
243
|
+
@m1.test_cases.should be_a_kind_of(Array)
|
244
|
+
@m1.test_cases.length.should == 1
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "scoring" do
|
249
|
+
before(:each) do
|
250
|
+
@m1 = EvaluateWithTestCases.new(name: :tester)
|
251
|
+
@m1.test_cases = (0...10).collect do |i|
|
252
|
+
TestCase.new(inputs: {"x1:int" => i}, outputs: {"y1" => 2*i, "y2" => 3*i})
|
253
|
+
end
|
254
|
+
@m1.build_sensor("y1") {|a| 777}
|
255
|
+
@m1.build_sensor("y2") {|a| 666}
|
256
|
+
|
257
|
+
@batch = Batch.[](Answer.new("do a"))
|
258
|
+
@i1 = Interpreter.new
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should make an Interpreter for each row of training data" do
|
262
|
+
@m1.stub!(:load_training_data!)
|
263
|
+
Interpreter.should_receive(:new).exactly(10).times.and_return(@i1)
|
264
|
+
@m1.score(@batch)
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should run all the Interpreters" do
|
268
|
+
@m1.stub!(:load_training_data!)
|
269
|
+
Interpreter.should_receive(:new).exactly(10).times.and_return(@i1)
|
270
|
+
@i1.should_receive(:run).at_least(1).times.and_return({})
|
271
|
+
@m1.score(@batch)
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should register its sensors before each Interpreter run" do
|
275
|
+
Interpreter.stub!(:new).and_return(@i1)
|
276
|
+
@i1.should_receive(:register_sensor).at_least(1).times
|
277
|
+
@m1.score(@batch)
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should have a score for each sensor" do
|
281
|
+
@m1.score(@batch)
|
282
|
+
@batch.first.scores["y1"].should_not == nil
|
283
|
+
@batch.first.scores["y2"].should_not == nil
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should return sum of absolute errors" do
|
287
|
+
@m1.stub!(:load_training_data!)
|
288
|
+
@m1.score(@batch)
|
289
|
+
@batch[0].scores["y1"].should == 777+775+773+771+769+767+765+763+761+759
|
290
|
+
@batch[0].scores["y2"].should == 666+663+660+657+654+651+648+645+642+639
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
end
|
296
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
describe "Machines::SelectBySummedRank" do
|
4
|
+
before(:each) do
|
5
|
+
@best = Machines::SelectBySummedRank.new
|
6
|
+
@highlander = Batch.[](Answer.new("foo"), Answer.new("bar"), Answer.new("baz"))
|
7
|
+
@highlander[0].scores = {e1:15, e2:12} # 3,3 = 6
|
8
|
+
@highlander[1].scores = {e1:5, e2:5} # 2,2 = 4
|
9
|
+
@highlander[2].scores = {e1:1, e2:1} # 1,1 = 2
|
10
|
+
|
11
|
+
@lowlander = Batch.[](Answer.new("foo"), Answer.new("bar"), Answer.new("baz"))
|
12
|
+
@lowlander[0].scores = {e1:1, e2:3} # 1,3 = 4
|
13
|
+
@lowlander[1].scores = {e1:2, e2:2} # 2,2 = 4
|
14
|
+
@lowlander[2].scores = {e1:3, e2:1} # 3,1 = 4
|
15
|
+
|
16
|
+
@allover = Batch.[](Answer.new("foo"), Answer.new("bar"), Answer.new("baz"))
|
17
|
+
@allover[0].scores = {e1:1, e2:3} # 1,2,-
|
18
|
+
@allover[1].scores = {e1:2, e2:2, e3:2} # 2,1,1
|
19
|
+
@allover[2].scores = {e1:3} # 3,-,-
|
20
|
+
|
21
|
+
@separate = Batch.[](Answer.new("foo"), Answer.new("bar"))
|
22
|
+
@separate[0].scores = {e1:1}
|
23
|
+
@separate[1].scores = {e2:2, e3:2}
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
describe "#screen method" do
|
28
|
+
it "should respond to :screen" do
|
29
|
+
@best.should respond_to(:screen)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should only accept a Batch as its argument" do
|
33
|
+
lambda{@best.screen(129)}.should raise_error
|
34
|
+
lambda{@best.screen([Answer.new("foo")])}.should raise_error
|
35
|
+
lambda{@best.screen(@highlander, comparison_criteria:[:e1])}.should_not raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should produce a Batch" do
|
39
|
+
@best.screen(@highlander, comparison_criteria:[:e2]).should be_a_kind_of(Batch)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should use the :comparison_criteria option as a template Array of score keys" do
|
43
|
+
ignore_most = @best.screen(@lowlander, comparison_criteria:[:e1])
|
44
|
+
ignore_most.length.should == 1
|
45
|
+
ignore_most.should include(@lowlander[0])
|
46
|
+
|
47
|
+
ignore_most = @best.screen(@lowlander, comparison_criteria:[:e2])
|
48
|
+
ignore_most.length.should == 1
|
49
|
+
ignore_most.should include(@lowlander[2])
|
50
|
+
|
51
|
+
ignore_most = @best.screen(@allover, comparison_criteria:[:e1])
|
52
|
+
ignore_most.length.should == 1
|
53
|
+
ignore_most.should include(@allover[0])
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should use the intersection of all the score keys in the :batch as a default for criteria" do
|
57
|
+
@best.should_receive(:shared_goals).and_return([:e1])
|
58
|
+
@best.screen(@highlander)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should accept (and store) an initialization :comparison_criteria option" do
|
62
|
+
just_one = Machines::SelectBySummedRank.new(comparison_criteria:[:e2]).
|
63
|
+
screen(@lowlander)
|
64
|
+
just_one.length.should == 1
|
65
|
+
just_one.should include(@lowlander[2])
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should include all Answers lacking a given score (since they can't be ranked)" do
|
69
|
+
dunno = @best.screen(@allover, comparison_criteria:[:e2])
|
70
|
+
dunno.length.should == 2
|
71
|
+
dunno.should include(@allover[1])
|
72
|
+
dunno.should include(@allover[2])
|
73
|
+
dunno.should_not include(@allover[0])
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return the entire batch if no scores are shared" do
|
77
|
+
@best.screen(@separate).length.should == 2
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should override its initialization if given a #build option" do
|
81
|
+
overridden = Machines::SelectBySummedRank.new(comparison_criteria:[:e2]).
|
82
|
+
screen(@lowlander,comparison_criteria:[:e1])
|
83
|
+
overridden.length.should == 1
|
84
|
+
overridden[0].scores.should == {e1:1, e2:3}
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return the lowest-ranking subset of the argument Batch" do
|
88
|
+
@best.screen(@lowlander).length.should == 3
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return objects from the argument, not clones" do
|
92
|
+
(@highlander.collect {|a| a.object_id}).should include(@best.screen(@highlander)[0].object_id)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return a new Batch object" do
|
96
|
+
@best.screen(@highlander).object_id.should_not == @highlander.object_id
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should not change the :progress of the Answers" do
|
100
|
+
@best.screen(@highlander).each {|a| a.progress.should == 0}
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
it "should respond to :generate as an alias to :screen" do
|
107
|
+
Machines::SelectBySummedRank.new.should respond_to(:generate)
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
describe "all_goals" do
|
112
|
+
it "should return an Array of score keys" do
|
113
|
+
@best.all_goals(@highlander).should == [:e1,:e2]
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should include every score key in the batch passed in" do
|
117
|
+
@best.all_goals(@allover).should == [:e1,:e2, :e3]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should have one copy of each score name" do
|
121
|
+
@best.all_goals(@highlander).find_all {|e| e == :e1}.length.should == 1
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
describe "shared_goals" do
|
127
|
+
it "should return an Array of only the shared score keys from the Batch passed in" do
|
128
|
+
@best.shared_goals(@highlander).should == [:e1,:e2]
|
129
|
+
@best.shared_goals(@allover).should == [:e1]
|
130
|
+
@best.shared_goals(@separate).should == []
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
@@ -4,6 +4,7 @@ describe "Machines::SelectNondominated" do
|
|
4
4
|
describe "#screen method" do
|
5
5
|
before(:each) do
|
6
6
|
@best = Machines::SelectNondominated.new
|
7
|
+
|
7
8
|
@highlander = Batch.[](Answer.new("foo"), Answer.new("bar"), Answer.new("baz"))
|
8
9
|
@highlander[0].scores = {e1:5, e2:15}
|
9
10
|
@highlander[1].scores = {e1:15,e2:5}
|
@@ -18,6 +19,10 @@ describe "Machines::SelectNondominated" do
|
|
18
19
|
@allover[0].scores = {e1:1, e2:3}
|
19
20
|
@allover[1].scores = {e1:2, e2:2, e3:2}
|
20
21
|
@allover[2].scores = {e1:3}
|
22
|
+
|
23
|
+
@separate = Batch.[](Answer.new("foo"), Answer.new("bar"))
|
24
|
+
@separate[0].scores = {e1:1}
|
25
|
+
@separate[1].scores = {e2:2, e3:2}
|
21
26
|
end
|
22
27
|
|
23
28
|
it "should respond to :screen" do
|
@@ -37,6 +42,7 @@ describe "Machines::SelectNondominated" do
|
|
37
42
|
it "should accept a template Array of score keys" do
|
38
43
|
@best.screen(@lowlander).length.should == 3
|
39
44
|
@best.screen(@lowlander,comparison_criteria:[:e2]).length.should == 1
|
45
|
+
@best.screen(@lowlander,comparison_criteria:[:e2]).should include(@lowlander[2])
|
40
46
|
end
|
41
47
|
|
42
48
|
it "should use an initialization template as well" do
|
@@ -56,6 +62,8 @@ describe "Machines::SelectNondominated" do
|
|
56
62
|
@best.screen(@allover, comparison_criteria:[:e1]).length.should == 1
|
57
63
|
@best.screen(@allover, comparison_criteria:[:e2]).length.should == 2
|
58
64
|
@best.screen(@allover, comparison_criteria:[:e3]).length.should == 3
|
65
|
+
|
66
|
+
@best.screen(@separate).should == @separate
|
59
67
|
end
|
60
68
|
|
61
69
|
it "should return the nondominated subset of the argument" do
|