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