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
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe "Factory configuration methods" do
|
5
|
+
describe "configatron integration" do
|
6
|
+
it "should respond to #configatron" do
|
7
|
+
Factory.new.should respond_to(:configatron)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
describe "configure_paths" do
|
13
|
+
it "should respond to #configure_paths" do
|
14
|
+
Factory.new.should respond_to(:configure_paths!)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should populate self.configatron.factory_root as the path to the project folder" do
|
18
|
+
this_spec_file_parent_path = File.expand_path("#{File.dirname(__FILE__)}/..")
|
19
|
+
f1 = Factory.new
|
20
|
+
f1.configure_paths!
|
21
|
+
f1.configatron.factory_root.should == this_spec_file_parent_path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
describe "factory name" do
|
27
|
+
it "should populate self.configatron.factory_name" do
|
28
|
+
f1 = Factory.new
|
29
|
+
f1.configure_constants!
|
30
|
+
f1.configatron.factory_name.should == "my_factory"
|
31
|
+
|
32
|
+
f1 = Factory.new("super_fancy")
|
33
|
+
f1.configure_constants!
|
34
|
+
f1.configatron.factory_name.should == "super_fancy"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
describe "database setup" do
|
40
|
+
describe "paths" do
|
41
|
+
it "should read from database.yml" do
|
42
|
+
f1 = Factory.new("super_fancy")
|
43
|
+
f1.configatron.should_receive(:configure_from_yaml)
|
44
|
+
f1.configure!
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "subject" do
|
48
|
+
before(:each) do
|
49
|
+
@f1 = Factory.new()
|
50
|
+
@f1.configure!
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should populate configatron.main_database.db_root" do
|
54
|
+
@f1.configatron.main_database.db_root.should == "http://127.0.0.1:5984"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should populate configatron.main_database.db_name" do
|
58
|
+
@f1.configatron.main_database.db_name.should == "my_factory" # from the config file
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should populate configatron.main_database.tag_filter" do
|
62
|
+
@f1.configatron.main_database.tag_filter.should == "_design/routing/_view/by_tag"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "checking for CouchDB access" do
|
69
|
+
it "should call Factory#couch_db?"
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "setting up initial db" do
|
73
|
+
it "should not remove old records unless asked to do so"
|
74
|
+
it "should be possible to erase the db if a flag is set"
|
75
|
+
it "should set up the design document"
|
76
|
+
it "should write the search-by-tag filter view to the design document"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
describe "Nudge language setup" do
|
82
|
+
it "should set up the Instructions"
|
83
|
+
|
84
|
+
it "should set up the Types"
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe "Factory" do
|
5
|
+
|
6
|
+
it "should have a name" do
|
7
|
+
Factory.new("foo_factory").name.should == "foo_factory"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a default name of 'something here'" do
|
11
|
+
Factory.new.name.should == "my_factory"
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "ontology" do
|
15
|
+
it "should have a master Instruction list" do
|
16
|
+
Factory.new("foo").instruction_library.should == Instruction.all_instructions
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be possible to override the default with an option" do
|
20
|
+
short_list = [IntAddInstruction, CodeNoopInstruction]
|
21
|
+
Factory.new("foo", instruction_library:short_list).instruction_library.should ==
|
22
|
+
short_list
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have a master NudgeType list" do
|
26
|
+
Factory.new("foo").type_library.should == NudgeType.all_types
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be possible to override the default with an option" do
|
30
|
+
short_list = [CodeType, BoolType]
|
31
|
+
Factory.new("foo", type_library:short_list).type_library.should ==
|
32
|
+
short_list
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should save all the Hash options it was called with" do
|
36
|
+
Factory.new("bar", my_option:1, my_other_option:[1,2,3]).original_options_hash.should ==
|
37
|
+
{:my_option=>1, :my_other_option=>[1, 2, 3]}
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "workstations" do
|
43
|
+
it "should have a list of extant workstation names" do
|
44
|
+
Factory.new.workstation_names.should == []
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "build_workstation" do
|
48
|
+
it "should create a new workstation"
|
49
|
+
it "should set up all the interior dynamics of the workstation"
|
50
|
+
it "should use the master config for defaults of the new workstation"
|
51
|
+
it "should suffice to create a pass-through workstation just to name it"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "activate" do
|
56
|
+
it "should have an #activate method"
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "databases" do
|
60
|
+
|
61
|
+
describe "#couch_available?" do
|
62
|
+
it "should have a method to check that couchDB is accessible" do
|
63
|
+
f1 = Factory.new("boo")
|
64
|
+
lambda{f1.couch_available?}.should_not raise_error
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return true if the uri is reachable" do
|
68
|
+
uri = "http://mycouch.db/boo"
|
69
|
+
f1 = Factory.new("boo")
|
70
|
+
f1.configatron.couchdb_uri = uri
|
71
|
+
FakeWeb.register_uri(:any, uri, :body => "We are here!", :status => [200, "OK"])
|
72
|
+
f1.couch_available?.should == true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return false if the uri is offline or 404's out" do
|
76
|
+
uri = "http://mycouch.db/boo"
|
77
|
+
f1 = Factory.new("boo", couchdb_uri:uri)
|
78
|
+
FakeWeb.register_uri(:any, uri, :body => "Go away!", :status => [404, "Not Found"])
|
79
|
+
f1.couch_available?.should == false
|
80
|
+
|
81
|
+
f1 = Factory.new("boo", couchdb_uri:"http://127.0.0.1:9991/place") # depends on this being wrong
|
82
|
+
f1.couch_available?.should == false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
describe "Workstation" do
|
4
|
+
|
5
|
+
describe "names" do
|
6
|
+
it "should have a name" do
|
7
|
+
Workstation.new(:my_workthing).name.should == :my_workthing
|
8
|
+
end
|
9
|
+
|
10
|
+
it "needs to have a symbol as a name" do
|
11
|
+
lambda{Workstation.new("foo")}.should raise_error(ArgumentError)
|
12
|
+
lambda{Workstation.new}.should raise_error(ArgumentError)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have a factory_name" do
|
16
|
+
Workstation.new(:ws).factory_name.should be_a_kind_of(String)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have a default factory_name of 'factory_name'" do
|
20
|
+
Workstation.new(:ws).factory_name.should == 'factory_name'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be possible to set the factory_name via an initialization option" do
|
24
|
+
Workstation.new(:ws, factory_name:'foo').factory_name.should == 'foo'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
describe "database" do
|
30
|
+
it "should have a URI for a CouchDB instance" do
|
31
|
+
Workstation.new(:ws).couchdb_uri.should be_a_kind_of(String)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should default to http://127.0.0.1:5984/\#{@factory_name}" do
|
35
|
+
Workstation.new(:ws).couchdb_uri.should == "http://127.0.0.1:5984/factory_name"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
describe "capacity" do
|
42
|
+
it "should accept a #capacity attribute in initialization" do
|
43
|
+
w1 = Workstation.new(:ws, capacity:12)
|
44
|
+
w1.capacity.should == 12
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have a default capacity of 100" do
|
48
|
+
Workstation.new(:ws).capacity.should == 100
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
describe "downstream_stations" do
|
54
|
+
it "should have an Array attribute called #downstream_stations" do
|
55
|
+
Workstation.new(:place).downstream_stations.should be_a_kind_of(Array)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "#downstream_stations should default to an empty Array" do
|
59
|
+
Workstation.new(:place).downstream_stations.should == []
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
describe "answers" do
|
65
|
+
it "should be an Array that's empty initially" do
|
66
|
+
Workstation.new(:place).answers.should == []
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
describe "transfer_answer" do
|
72
|
+
before(:each) do
|
73
|
+
@a1 = Answer.new("do a", tags:[:here])
|
74
|
+
@w1 = Workstation.new(:here)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should change the location tag of the Answer by removing self.name and adding destination.name" do
|
78
|
+
@w1.transfer_answer(@a1, :there)
|
79
|
+
@a1.tags.should include(:there)
|
80
|
+
@a1.tags.should_not include(:here)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should validate that the new location (tag) is a Symbol" do
|
84
|
+
lambda{@w1.transfer_answer(@a1, "garbage")}.should raise_error(ArgumentError)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should not change state if the ne location name is invalid" do
|
88
|
+
lambda{@w1.transfer_answer(@a1, "garbage")}.should raise_error(ArgumentError)
|
89
|
+
@a1.tags.should include(:here)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
describe "#cycle" do
|
97
|
+
it "should invoke #receive!, #build!, #ship! and #scrap!" do
|
98
|
+
w1 = Workstation.new(:place)
|
99
|
+
w1.should_receive(:receive!)
|
100
|
+
w1.should_receive(:build!)
|
101
|
+
w1.should_receive(:ship!)
|
102
|
+
w1.should_receive(:scrap!)
|
103
|
+
w1.cycle
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
describe "#receive!" do
|
108
|
+
it "should access its persistent store"
|
109
|
+
it "should gather its 'current' work_in_process into self#answers"
|
110
|
+
it "should gather its 'current' collaborators' work_in_process into self#collaborator_answers"
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
describe "#build!" do
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
describe "#ship!" do
|
120
|
+
it "should be an Array of stored procedures"
|
121
|
+
it "should always include (as a last entry) a Proc that returns 'false'"
|
122
|
+
it "should call all the Procs in order, for every member of its population"
|
123
|
+
it "should select a random downstream destination if none is specified by the rule"
|
124
|
+
it "should fail silently if there are no downstream stations"
|
125
|
+
it "should call every rule, in turn, sending every Answer off before moving on"
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
describe "scrap!" do
|
130
|
+
it "should be an Array of stored procedures"
|
131
|
+
it "should return 'true' to indicate that a particular Answer should be scrapped"
|
132
|
+
it "should use an Array of stored procedures"
|
133
|
+
it "should return a single boolean to indicate that scrapping should continue"
|
134
|
+
it "should always include (as a last entry) a Proc that checks whether population > capacity"
|
135
|
+
it "should set the workstation of scrapped Answers to Scrapyard"
|
136
|
+
it "should call rules in order, scrapping all indicated Answers, until scrap_trigger? is false"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
describe AnyOneSampler do
|
4
|
+
before(:each) do
|
5
|
+
@ao = AnyOneSampler.new
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
describe "#generate" do
|
10
|
+
before(:each) do
|
11
|
+
@dudes = Batch[Answer.new(""), Answer.new(""), Answer.new("")]
|
12
|
+
@dudes[0].scores = Hash["first", 2, "second", 20, "third", 200]
|
13
|
+
@dudes[1].scores = Hash["first", 20, "second", 200, "third", 2]
|
14
|
+
@dudes[2].scores = Hash["first", 200, "second", 2, "third", 20]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should take a Batch as a first parameter" do
|
18
|
+
lambda{@ao.generate()}.should raise_error(ArgumentError)
|
19
|
+
lambda{@ao.generate(@dudes)}.should_not raise_error(ArgumentError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return a Batch" do
|
23
|
+
@ao.generate(@dudes).should be_a_kind_of(Batch)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return a Batch containing references to Answers in the original Batch" do
|
27
|
+
one = @ao.generate(@dudes)
|
28
|
+
one.length.should == 1
|
29
|
+
one.each {|dude| @dudes.should include(dude)}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should invoke Batch#sample" do
|
33
|
+
@dudes.should_receive(:sample).and_return(@dudes[0])
|
34
|
+
one = @ao.generate(@dudes)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
|
4
|
+
describe DominatedQuantileSampler do
|
5
|
+
before(:each) do
|
6
|
+
@dq = DominatedQuantileSampler.new
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
describe "domination_classes" do
|
11
|
+
before(:each) do
|
12
|
+
@dudes = Batch[Answer.new("block {}"), Answer.new("do int_add")]
|
13
|
+
@dudes[0].scores["first"] = 120
|
14
|
+
@dudes[1].scores["first"] = 2
|
15
|
+
@dudes[0].scores["second"] = 2
|
16
|
+
@dudes[1].scores["second"] = 120
|
17
|
+
@dudes[0].scores["third"] = 20
|
18
|
+
@dudes[1].scores["third"] = 1200
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should take a Batch as an argument" do
|
22
|
+
lambda{@dq.domination_classes()}.should raise_error(ArgumentError)
|
23
|
+
lambda{@dq.domination_classes(@dudes)}.should_not raise_error(ArgumentError)
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can take a template of objective names to use" do
|
28
|
+
lambda{@dq.domination_classes(@dudes, ["first"])}.should_not raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return a Hash" do
|
32
|
+
@dq.domination_classes(@dudes, ["first"]).should be_a_kind_of(Hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should use the count of dominating Answers as the key" do
|
36
|
+
@dq.domination_classes(@dudes, ["second"]).keys.should == [0,1]
|
37
|
+
@dq.domination_classes(@dudes).keys.should == [0]
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should have an Array of the Answers in that class as the value" do
|
42
|
+
@dq.domination_classes(@dudes, ["first"])[0].length.should == 1
|
43
|
+
@dq.domination_classes(@dudes, ["first"])[0][0].should == @dudes[1]
|
44
|
+
@dq.domination_classes(@dudes, ["second"])[0].length.should == 1
|
45
|
+
@dq.domination_classes(@dudes, ["second"])[0][0].should == @dudes[0]
|
46
|
+
@dq.domination_classes(@dudes, ["second", "third"])[0].length.should == 1
|
47
|
+
@dq.domination_classes(@dudes, ["second", "third"])[0][0].should == @dudes[0]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
describe "#generate" do
|
53
|
+
before(:each) do
|
54
|
+
@dudes = Batch[Answer.new("do int_subtract"), Answer.new("do int_add")]
|
55
|
+
@dudes[0].scores["first"] = 120
|
56
|
+
@dudes[1].scores["first"] = 2
|
57
|
+
@dudes[0].scores["second"] = 2
|
58
|
+
@dudes[1].scores["second"] = 120
|
59
|
+
@dudes[0].scores["third"] = 20
|
60
|
+
@dudes[1].scores["third"] = 1200
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should take a Batch as a first parameter" do
|
64
|
+
lambda{@dq.generate()}.should raise_error(ArgumentError)
|
65
|
+
lambda{@dq.generate(@dudes)}.should_not raise_error(ArgumentError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return a Batch" do
|
69
|
+
@dq.generate(@dudes).should be_a_kind_of(Batch)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return a Batch containing references to individuals in the original Batch" do
|
73
|
+
half = @dq.generate(@dudes)
|
74
|
+
half.length.should be > 0
|
75
|
+
half.each {|dude| @dudes.should include(dude)}
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should have a parameter that specifies what fraction to return" do
|
79
|
+
some = @dq.generate(@dudes,1.0)
|
80
|
+
some.length.should == 2
|
81
|
+
|
82
|
+
some = @dq.generate(@dudes,0.5)
|
83
|
+
some.length.should == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should always return at least one for a non-zero fraction" do
|
87
|
+
some = @dq.generate(@dudes,0.01)
|
88
|
+
some.length.should be > 0
|
89
|
+
some.each {|dude| @dudes.should include(dude)}
|
90
|
+
|
91
|
+
some = @dq.generate(@dudes,0)
|
92
|
+
some.length.should == 0
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
it "should take a template of objectives to use in sorting" do
|
97
|
+
@dq.generate(@dudes,0.5,["first"]).should include(@dudes[0])
|
98
|
+
@dq.generate(@dudes,0.5,["second"]).should include(@dudes[1])
|
99
|
+
@dq.generate(@dudes,0.5,["second", "third"]).should include(@dudes[1])
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return the most-dominated Answers first, nondominated last" do
|
103
|
+
some = @dq.generate(@dudes,1, ["first"])
|
104
|
+
some[0].should == @dudes[0]
|
105
|
+
|
106
|
+
some = @dq.generate(@dudes,1, ["second"])
|
107
|
+
some[0].should == @dudes[1]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|