answer-factory 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/LICENSE.txt +21 -0
  2. data/Rakefile +29 -0
  3. data/Thorfile +79 -0
  4. data/VERSION +1 -0
  5. data/_spikes/old_vs_new_dominated_by?.rb +45 -0
  6. data/config/database.yml +9 -0
  7. data/lib/answer-factory.rb +14 -0
  8. data/lib/answers/answer.rb +126 -0
  9. data/lib/answers/batch.rb +49 -0
  10. data/lib/factories/factory.rb +53 -0
  11. data/lib/factories/workstation.rb +33 -0
  12. data/lib/operators/basic_operators.rb +240 -0
  13. data/lib/operators/evaluators.rb +113 -0
  14. data/lib/operators/samplers_and_selectors.rb +131 -0
  15. data/pkg/nudgegp-0.0.1.gem +0 -0
  16. data/readme.md +29 -0
  17. data/spec/answer_spec.rb +412 -0
  18. data/spec/batch_spec.rb +98 -0
  19. data/spec/config_spec.rb +94 -0
  20. data/spec/factories/factory_spec.rb +86 -0
  21. data/spec/factories/workstation_spec.rb +139 -0
  22. data/spec/operators/any_one_sampler_spec.rb +39 -0
  23. data/spec/operators/dominated_quantile_spec.rb +111 -0
  24. data/spec/operators/duplicate_genomes_spec.rb +35 -0
  25. data/spec/operators/evaluators/program_point_evaluator_spec.rb +43 -0
  26. data/spec/operators/evaluators/test_case_evaluator_spec.rb +129 -0
  27. data/spec/operators/infrastructure_spec.rb +45 -0
  28. data/spec/operators/most_dominated_subset_spec.rb +47 -0
  29. data/spec/operators/nondominated_subset_spec.rb +103 -0
  30. data/spec/operators/pointCrossover_spec.rb +60 -0
  31. data/spec/operators/pointDeletion_spec.rb +62 -0
  32. data/spec/operators/pointMutation_spec.rb +77 -0
  33. data/spec/operators/random_guess_spec.rb +77 -0
  34. data/spec/operators/resample_and_clone_spec.rb +60 -0
  35. data/spec/operators/resample_values_spec.rb +135 -0
  36. data/spec/operators/uniformBackboneCrossover_spec.rb +67 -0
  37. data/spec/spec_helper.rb +14 -0
  38. metadata +201 -0
@@ -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