answer-factory 0.0.1
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/LICENSE.txt +21 -0
- data/Rakefile +29 -0
- data/Thorfile +79 -0
- data/VERSION +1 -0
- data/_spikes/old_vs_new_dominated_by?.rb +45 -0
- data/config/database.yml +9 -0
- data/lib/answer-factory.rb +14 -0
- data/lib/answers/answer.rb +126 -0
- data/lib/answers/batch.rb +49 -0
- data/lib/factories/factory.rb +53 -0
- data/lib/factories/workstation.rb +33 -0
- data/lib/operators/basic_operators.rb +240 -0
- data/lib/operators/evaluators.rb +113 -0
- data/lib/operators/samplers_and_selectors.rb +131 -0
- data/pkg/nudgegp-0.0.1.gem +0 -0
- data/readme.md +29 -0
- data/spec/answer_spec.rb +412 -0
- data/spec/batch_spec.rb +98 -0
- data/spec/config_spec.rb +94 -0
- data/spec/factories/factory_spec.rb +86 -0
- data/spec/factories/workstation_spec.rb +139 -0
- data/spec/operators/any_one_sampler_spec.rb +39 -0
- data/spec/operators/dominated_quantile_spec.rb +111 -0
- data/spec/operators/duplicate_genomes_spec.rb +35 -0
- data/spec/operators/evaluators/program_point_evaluator_spec.rb +43 -0
- data/spec/operators/evaluators/test_case_evaluator_spec.rb +129 -0
- data/spec/operators/infrastructure_spec.rb +45 -0
- data/spec/operators/most_dominated_subset_spec.rb +47 -0
- data/spec/operators/nondominated_subset_spec.rb +103 -0
- data/spec/operators/pointCrossover_spec.rb +60 -0
- data/spec/operators/pointDeletion_spec.rb +62 -0
- data/spec/operators/pointMutation_spec.rb +77 -0
- data/spec/operators/random_guess_spec.rb +77 -0
- data/spec/operators/resample_and_clone_spec.rb +60 -0
- data/spec/operators/resample_values_spec.rb +135 -0
- data/spec/operators/uniformBackboneCrossover_spec.rb +67 -0
- data/spec/spec_helper.rb +14 -0
- metadata +201 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe AllDuplicatedGenomesSampler do
|
5
|
+
before(:each) do
|
6
|
+
@dg = AllDuplicatedGenomesSampler.new
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
describe "#generate" do
|
11
|
+
before(:each) do
|
12
|
+
@dudes = Batch[Answer.new("block {}"), Answer.new("block {}"), Answer.new("do int_add")]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should take a Batch as a first parameter" do
|
16
|
+
lambda{@dg.generate()}.should raise_error(ArgumentError)
|
17
|
+
lambda{@dg.generate(@dudes)}.should_not raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return a Batch" do
|
21
|
+
@dg.generate(@dudes).should be_a_kind_of(Batch)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return a Batch containing references to individuals in the original Batch" do
|
25
|
+
repeats = @dg.generate(@dudes)
|
26
|
+
repeats.length.should == 2
|
27
|
+
repeats.each {|dude| @dudes.should include(dude)}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return an empty Batch if there are no duplicates" do
|
31
|
+
@dudes.delete_at(0)
|
32
|
+
@dg.generate(@dudes).should be_empty
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe ProgramPointEvaluator do
|
5
|
+
|
6
|
+
describe "initialization" do
|
7
|
+
it "should have an objective name set upon initialization" do
|
8
|
+
lambda{ProgramPointEvaluator.new}.should raise_error(ArgumentError)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#evaluate" do
|
13
|
+
before(:each) do
|
14
|
+
@ppe = ProgramPointEvaluator.new(:name => :point_count)
|
15
|
+
@dudes = Batch[
|
16
|
+
Answer.new("block {}"),
|
17
|
+
Answer.new("block { block {}}"),
|
18
|
+
Answer.new("block { block { block {}}}")
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should take a Batch of individuals as an argument" do
|
23
|
+
lambda{@ppe.evaluate(Answer.new("block {}"))}.should raise_error(ArgumentError)
|
24
|
+
lambda{@ppe.evaluate(Batch[Answer.new("block {}")])}.should_not raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should raise an exception if it can't evaluate an Answer" do
|
28
|
+
lambda{@ppe.evaluate(Batch[Answer.new("blah_de_blah")])}.should raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should write the number of program points into each individual" do
|
32
|
+
@dudes.each {|dude| dude.scores[:point_count].should == nil}
|
33
|
+
@ppe.evaluate(@dudes)
|
34
|
+
@dudes.collect {|dude| dude.scores[:point_count]}.should == [1,2,3]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the same Batch it got, with updated values" do
|
38
|
+
origIDs = @dudes.collect {|dude| dude.object_id}
|
39
|
+
@ppe.evaluate(@dudes)
|
40
|
+
@dudes.each {|dude| origIDs.should include(dude.object_id)}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), "./../../spec_helper")
|
3
|
+
|
4
|
+
|
5
|
+
describe TestCase do
|
6
|
+
describe "bindings" do
|
7
|
+
it "should have a Hash of independent variable names and assigned values" do
|
8
|
+
TestCase.new.should respond_to(:bindings)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "expectations" do
|
13
|
+
it "should have a Hash of dependent variable names and expected values" do
|
14
|
+
TestCase.new.should respond_to(:expectations)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "gauges" do
|
19
|
+
it "should have a Hash of Proc objects that measure the observed values" do
|
20
|
+
TestCase.new.should respond_to(:gauges)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have one gauge for every expectation" do
|
24
|
+
lambda{TestCase.new(
|
25
|
+
:expectations => {"y1"=>ValuePoint.new("int", 31)},
|
26
|
+
:gauges => {"h"=>Proc.new {} } )}.should raise_error
|
27
|
+
lambda{TestCase.new(
|
28
|
+
:expectations => {"y1"=>ValuePoint.new("int", 31)},
|
29
|
+
:gauges => {"y1"=>Proc.new {} } )}.should_not raise_error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
describe TestCaseEvaluator do
|
39
|
+
describe "initialize" do
|
40
|
+
it "should have a name" do
|
41
|
+
lambda{TestCaseEvaluator.new()}.should raise_error(ArgumentError)
|
42
|
+
lambda{TestCaseEvaluator.new(name:"boolean_multiplexer_SSE")}.should_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should have all the info it needs to set up an Interpreter"
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "evaluate" do
|
49
|
+
before(:each) do
|
50
|
+
@tce = TestCaseEvaluator.new(:name => :error)
|
51
|
+
@dudes = Batch[
|
52
|
+
Answer.new("value «int»\n«int» 12"),
|
53
|
+
Answer.new("value «int»\n«int» -9912"),
|
54
|
+
Answer.new("value «bool»\n«bool» false"),
|
55
|
+
Answer.new("block { value «int» value «int»}\n«int» 99\n«int» 12")
|
56
|
+
]
|
57
|
+
@cases = [
|
58
|
+
TestCase.new(:bindings => {"x" => ValuePoint.new("int",77)},
|
59
|
+
:expectations => {"y" => 12},
|
60
|
+
:gauges => {"y" => Proc.new {|interp| interp.stacks[:int].peek}}
|
61
|
+
),
|
62
|
+
TestCase.new(:bindings => {"x" => ValuePoint.new("int",78)},
|
63
|
+
:expectations => {"y" => 13},
|
64
|
+
:gauges => {"y" => Proc.new {|interp| interp.stacks[:int].peek}}
|
65
|
+
)
|
66
|
+
]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should raise an exception if the batch argument isn't a Batch" do
|
70
|
+
lambda{@tce.evaluate()}.should raise_error(ArgumentError)
|
71
|
+
lambda{@tce.evaluate(@dudes)}.should_not raise_error(ArgumentError)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should assign a numeric score to all the Answers in the Batch" do
|
75
|
+
@dudes.each {|dude| dude.scores[:error].should == nil}
|
76
|
+
@tce.evaluate(@dudes, @cases)
|
77
|
+
@dudes.each {|dude| dude.scores[:error].kind_of?(Numeric).should == true}
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should create an Interpreter for each run" do
|
81
|
+
myI = Interpreter.new
|
82
|
+
Interpreter.should_receive(:new).exactly(8).times.and_return(myI)
|
83
|
+
@tce.evaluate(@dudes, @cases)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should be reset each time before running them" do
|
87
|
+
myI = Interpreter.new
|
88
|
+
Interpreter.stub!(:new).and_return(myI)
|
89
|
+
myI.should_receive(:reset).exactly(8).times
|
90
|
+
@tce.evaluate(@dudes, @cases)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should set up bindings before running them" do
|
94
|
+
myI = Interpreter.new
|
95
|
+
Interpreter.stub!(:new).and_return(myI)
|
96
|
+
myI.should_receive(:bind_variable).exactly(8).times
|
97
|
+
@tce.evaluate(@dudes, @cases)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should run each TestCase for each individual in the Batch" do
|
101
|
+
myI = Interpreter.new
|
102
|
+
Interpreter.stub!(:new).and_return(myI)
|
103
|
+
myI.should_receive(:run).exactly(8).times
|
104
|
+
@tce.evaluate(@dudes, @cases)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "after running a TestCase using an Answer, all the gauges should be called" do
|
108
|
+
myI = Interpreter.new
|
109
|
+
Interpreter.stub!(:new).and_return(myI)
|
110
|
+
myI.should_receive(:run).exactly(8).times
|
111
|
+
@tce.evaluate(@dudes, @cases)
|
112
|
+
|
113
|
+
myI.should_receive(:run).exactly(4).times
|
114
|
+
@tce.evaluate(@dudes, [TestCase.new(:gauges => {"a" => Proc.new {|interp|}})])
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should synthesize the gauge readings into a single numerical score"
|
118
|
+
|
119
|
+
it "should loop over the test cases to collect the error" do
|
120
|
+
@dudes.each {|dude| dude.scores[:error].should == nil}
|
121
|
+
|
122
|
+
@tce.evaluate(@dudes, @cases)
|
123
|
+
equal12or13error = @dudes.collect {|dude| dude.scores[:error]}
|
124
|
+
expectedScores = [1, 19849, 200000, 1]
|
125
|
+
(0..3).each {|i| equal12or13error[i].should be_close(expectedScores[i].to_f / 2, 0.0001)}
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe "domination_classes" do
|
5
|
+
before(:each) do
|
6
|
+
@dq = Sampler.new
|
7
|
+
|
8
|
+
@dudes = Batch[Answer.new("block {}"), Answer.new("do int_add")]
|
9
|
+
@dudes[0].scores["first"] = 120
|
10
|
+
@dudes[1].scores["first"] = 2
|
11
|
+
@dudes[0].scores["second"] = 2
|
12
|
+
@dudes[1].scores["second"] = 120
|
13
|
+
@dudes[0].scores["third"] = 20
|
14
|
+
@dudes[1].scores["third"] = 1200
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should take a Batch as an argument" do
|
18
|
+
lambda{@dq.domination_classes()}.should raise_error(ArgumentError)
|
19
|
+
lambda{@dq.domination_classes(@dudes)}.should_not raise_error(ArgumentError)
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can take a template of objective names to use" do
|
24
|
+
lambda{@dq.domination_classes(@dudes, ["first"])}.should_not raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return a Hash" do
|
28
|
+
@dq.domination_classes(@dudes, ["first"]).should be_a_kind_of(Hash)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should use the count of dominating Answers as the key" do
|
32
|
+
@dq.domination_classes(@dudes, ["second"]).keys.should == [0,1]
|
33
|
+
@dq.domination_classes(@dudes).keys.should == [0]
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have an Array of the Answers in that class as the value" do
|
38
|
+
@dq.domination_classes(@dudes, ["first"])[0].length.should == 1
|
39
|
+
@dq.domination_classes(@dudes, ["first"])[0][0].should == @dudes[1]
|
40
|
+
@dq.domination_classes(@dudes, ["second"])[0].length.should == 1
|
41
|
+
@dq.domination_classes(@dudes, ["second"])[0][0].should == @dudes[0]
|
42
|
+
@dq.domination_classes(@dudes, ["second", "third"])[0].length.should == 1
|
43
|
+
@dq.domination_classes(@dudes, ["second", "third"])[0][0].should == @dudes[0]
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe MostDominatedSubsetSampler do
|
5
|
+
before(:each) do
|
6
|
+
@md = MostDominatedSubsetSampler.new
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
describe "#generate" do
|
11
|
+
before(:each) do
|
12
|
+
@dudes = Batch[Answer.new("block {}"), Answer.new("block {}"), Answer.new("block {}")]
|
13
|
+
@dudes[0].scores = Hash[:first, 2, :second, 20, :third, 200]
|
14
|
+
@dudes[1].scores = Hash[:first, 20, :second, 200, :third, 2]
|
15
|
+
@dudes[2].scores = Hash[:first, 200, :second, 2, :third, 20]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should take a Batch as a first parameter" do
|
19
|
+
lambda{@md.generate()}.should raise_error(ArgumentError)
|
20
|
+
lambda{@md.generate(@dudes)}.should_not raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return a Batch" do
|
24
|
+
@md.generate(@dudes).should be_a_kind_of(Batch)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return a Batch containing references to individuals in the original Batch" do
|
28
|
+
half = @md.generate(@dudes)
|
29
|
+
half.length.should be > 0
|
30
|
+
half.each {|dude| @dudes.should include(dude)}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should always return at least one, even when everybody is nondominated" do
|
34
|
+
some = @md.generate(@dudes)
|
35
|
+
some.length.should == 3
|
36
|
+
some.each {|dude| @dudes.should include(dude)}
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "should take a template of objectives to use in sorting" do
|
41
|
+
@md.generate(@dudes,[:first]).should include(@dudes[2])
|
42
|
+
@md.generate(@dudes,[:second]).should include(@dudes[1])
|
43
|
+
@md.generate(@dudes,[:second, :third]).should include(@dudes[0])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe "nondominated_subset operator" do
|
5
|
+
before(:each) do
|
6
|
+
@myNondominatedScreener = NondominatedSubsetSelector.new
|
7
|
+
@params = {points:3, instruction_names:[:int_add, :int_multiply], type_names:["int"]}
|
8
|
+
@myGuesser = RandomGuessOperator.new(@params)
|
9
|
+
@twoGuys = @myGuesser.generate(2)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be a kind of SearchOperator" do
|
13
|
+
@myNondominatedScreener.should be_a_kind_of(SearchOperator)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "the #all_known_criteria method should return an Array with the union of all scores keys in the crowd" do
|
17
|
+
@twoGuys[0].scores = {x2:612, y2:77, x3:712}
|
18
|
+
@twoGuys[1].scores = {y1:2, x1:3, x2:4}
|
19
|
+
@myNondominatedScreener.all_known_criteria(@twoGuys).sort.should == [:x1,:x2, :x3, :y1, :y2].sort
|
20
|
+
end
|
21
|
+
|
22
|
+
it "the #all_shared_scores method should return an Array of the keys of the #scores hashes in the crowd" do
|
23
|
+
twoGuys = @myGuesser.generate(2)
|
24
|
+
twoGuys[0].scores = {x2:612, x1:77, x3:712}
|
25
|
+
twoGuys[1].scores = {x2:2, x1:3, x3:4}
|
26
|
+
@myNondominatedScreener.all_shared_scores(twoGuys).sort.should == [:x1,:x2, :x3].sort
|
27
|
+
|
28
|
+
twoGuys[0].scores = {x3:712, :something_else => 88}
|
29
|
+
twoGuys[1].scores = {x2:2, :x1 => 3, :x3 => 4}
|
30
|
+
@myNondominatedScreener.all_shared_scores(twoGuys).sort.should == [:x3].sort
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should produce a Batch of Answer objects when it receives #generate; at least one" do
|
34
|
+
twoGuys = @myGuesser.generate(2)
|
35
|
+
twoGuys[0].scores = {:x2 => 612, :x1 => 77, :x3 => 712}
|
36
|
+
twoGuys[1].scores = {:x2 => 2, :x1 => 3, :x3 => 4}
|
37
|
+
@myNondominatedScreener.generate(twoGuys).should be_a_kind_of(Batch)
|
38
|
+
@myNondominatedScreener.generate(twoGuys)[0].should be_a_kind_of(Answer)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should work, passing along references not clones to the original guys" do
|
42
|
+
twoGuys = @myGuesser.generate(2)
|
43
|
+
twoGuys[0].scores = {x2:612, x1:77, x3:712}
|
44
|
+
twoGuys[1].scores = {x2:2, x1:3, x3:4}
|
45
|
+
@myNondominatedScreener.generate(twoGuys).should include(twoGuys[1])
|
46
|
+
@myNondominatedScreener.generate(twoGuys).should_not include(twoGuys[0])
|
47
|
+
|
48
|
+
|
49
|
+
twoGuys[0].scores = {:x2 => 1, :x1 => 2, :x3 => 3}
|
50
|
+
twoGuys[1].scores = {:x2 => 2, :x1 => 1, :x3 => 3}
|
51
|
+
@myNondominatedScreener.generate(twoGuys).length.should == 2
|
52
|
+
@myNondominatedScreener.generate(twoGuys).should include(twoGuys[0])
|
53
|
+
@myNondominatedScreener.generate(twoGuys).should include(twoGuys[1])
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should work the same no matter what the scores hash order" do
|
57
|
+
twoGuys = @myGuesser.generate(2)
|
58
|
+
twoGuys[0].scores = {:x1 => 77, :x3 => 712,:x2 => 612}
|
59
|
+
twoGuys[1].scores = {:x2 => 2, :x1 => 3, :x3 => 4}
|
60
|
+
@myNondominatedScreener.generate(twoGuys).should include(twoGuys[1])
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
it "can use the 'template' parameter to compare individuals by a specified vector of scores" do
|
65
|
+
threeGuys = @myGuesser.generate(3)
|
66
|
+
threeGuys[0].scores = {:x1 => 1, :x2 => 2, :x3 => 3}
|
67
|
+
threeGuys[1].scores = {:x1 => 2, :x2 => 1, :x3 => 1}
|
68
|
+
threeGuys[2].scores = {:x1 => 4, :x2 => 0, :x3 => 2}
|
69
|
+
@myNondominatedScreener.generate(threeGuys).length.should == 3
|
70
|
+
@myNondominatedScreener.generate(threeGuys,[:x1]).length.should == 1
|
71
|
+
@myNondominatedScreener.generate(threeGuys,[:x1]).should include(threeGuys[0])
|
72
|
+
@myNondominatedScreener.generate(threeGuys,[:x2]).length.should == 1
|
73
|
+
@myNondominatedScreener.generate(threeGuys,[:x2]).should include(threeGuys[2])
|
74
|
+
@myNondominatedScreener.generate(threeGuys,[:x3]).length.should == 1
|
75
|
+
@myNondominatedScreener.generate(threeGuys,[:x3]).should include(threeGuys[1])
|
76
|
+
@myNondominatedScreener.generate(threeGuys,[:x1,:x3]).length.should == 2
|
77
|
+
@myNondominatedScreener.generate(threeGuys,[:x1,:x2]).length.should == 3
|
78
|
+
@myNondominatedScreener.generate(threeGuys,[:x2,:x3]).length.should == 2
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
it "should not include Answers in the resulting Batch that have not got the specified scores"
|
83
|
+
|
84
|
+
|
85
|
+
it "should use a default 'template' parameter that's the intersection of scores keys in the crowd" do
|
86
|
+
twoGuys = @myGuesser.generate(2)
|
87
|
+
twoGuys[0].scores = {x1:1, x2:2, x3:3}
|
88
|
+
twoGuys[1].scores = { x2:0, x4:12}
|
89
|
+
|
90
|
+
@myNondominatedScreener.generate(twoGuys).length.should == 1
|
91
|
+
@myNondominatedScreener.generate(twoGuys).should include twoGuys[1]
|
92
|
+
@myNondominatedScreener.generate(twoGuys,[:x2]).length.should == 1
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return Answers that belonged to crowd passed in" do
|
96
|
+
twoGuys = @myGuesser.generate(2)
|
97
|
+
orig_IDs = twoGuys.collect {|dude| dude.object_id}
|
98
|
+
twoGuys[0].scores = {:x1 => 1, :x2 => 2, :x3 => 3}
|
99
|
+
twoGuys[1].scores = { :x2 => 1, :x4 => 3}
|
100
|
+
@myNondominatedScreener.generate(twoGuys).length.should == 1
|
101
|
+
@myNondominatedScreener.generate(twoGuys).each {|newDude| orig_IDs.should include(newDude.object_id)}
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe "PointCrossoverOperator" do
|
5
|
+
before(:each) do
|
6
|
+
@myXover = PointCrossoverOperator.new
|
7
|
+
@dude1 = Answer.new("block{do a \n do b\n do c}")
|
8
|
+
@dude2 = Answer.new("block{ref x \n ref y\n ref z}")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be a kind of SearchOperator" do
|
12
|
+
@myXover.should be_a_kind_of(SearchOperator)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
describe "generate" do
|
17
|
+
|
18
|
+
it "should take as a param a set of one or more Answers" do
|
19
|
+
lambda{@myXover.generate()}.should raise_error(ArgumentError)
|
20
|
+
lambda{@myXover.generate(331)}.should raise_error(ArgumentError)
|
21
|
+
lambda{@myXover.generate([])}.should raise_error(ArgumentError)
|
22
|
+
lambda{@myXover.generate([11])}.should raise_error(ArgumentError)
|
23
|
+
|
24
|
+
lambda{@myXover.generate([@dude1])}.should_not raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should produce the same number of Answers it gets as a default" do
|
28
|
+
babies = @myXover.generate([@dude1])
|
29
|
+
babies.length.should == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have an optional parameter that specifies the number of offspring to produce per parent" do
|
33
|
+
babies = @myXover.generate(Batch.[](@dude1, @dude2))
|
34
|
+
babies.length.should == 2
|
35
|
+
babies = @myXover.generate([@dude1, @dude2],4)
|
36
|
+
babies.length.should == 8
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should only include points from one of the parents in the offspring blueprints" do
|
40
|
+
babies = @myXover.generate([@dude1, @dude2])
|
41
|
+
bothGenomes = @dude1.program.blueprint + @dude2.program.blueprint
|
42
|
+
babies.each do |baby|
|
43
|
+
baby.program.blueprint.each_line do |line|
|
44
|
+
bothGenomes.match(line.strip.delete("}")).should_not == nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should handle moving the footnotes correctly"
|
50
|
+
|
51
|
+
it "should maintain unused footnotes correctly"
|
52
|
+
|
53
|
+
it "should increment the offspring's progress from the max parents' progress" do
|
54
|
+
@dude1.stub(:progress).and_return(7)
|
55
|
+
@dude2.stub(:progress).and_return(11)
|
56
|
+
babies = @myXover.generate([@dude1, @dude2],10)
|
57
|
+
babies.each {|baby| [8,12].should include(baby.progress)}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|