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
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
|