answer-factory 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|