answer-factory 0.1.2 → 0.1.3.4
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.
- 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
|