answer-factory 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/Rakefile +1 -0
  2. data/Thorfile +9 -6
  3. data/VERSION +1 -1
  4. data/answer-factory.gemspec +20 -5
  5. data/lib/answer-factory.rb +14 -2
  6. data/lib/answers/answer.rb +17 -3
  7. data/lib/answers/batch.rb +15 -3
  8. data/lib/factories/workstation.rb +50 -1
  9. data/lib/operators/all_duplicated_genomes_sampler.rb +14 -0
  10. data/lib/operators/any_one_sampler.rb +7 -0
  11. data/lib/operators/dominated_quantile_selector.rb +16 -0
  12. data/lib/operators/infrastructure.rb +74 -0
  13. data/lib/operators/most_dominated_subset_sampler.rb +13 -0
  14. data/lib/operators/nondominated_subset_selector.rb +17 -0
  15. data/lib/operators/point_crossover_operator.rb +24 -0
  16. data/lib/operators/point_delete_operator.rb +19 -0
  17. data/lib/operators/point_mutation_operator.rb +22 -0
  18. data/lib/operators/program_point_count_evaluator.rb +14 -0
  19. data/lib/operators/random_guess_operator.rb +30 -0
  20. data/lib/operators/resample_and_clone_operator.rb +28 -0
  21. data/lib/operators/resample_values_operator.rb +40 -0
  22. data/lib/operators/{evaluators.rb → test_case_evaluator.rb} +3 -34
  23. data/lib/operators/uniform_backbone_crossover_operator.rb +53 -0
  24. data/readme.md +28 -3
  25. data/spec/answer_spec.rb +33 -1
  26. data/spec/batch_spec.rb +25 -12
  27. data/spec/factories/factory_spec.rb +53 -36
  28. data/spec/factories/workstation_spec.rb +194 -20
  29. data/spec/operators/evaluators/program_point_evaluator_spec.rb +1 -1
  30. data/spec/operators/evaluators/test_case_evaluator_spec.rb +2 -2
  31. data/spec/operators/nondominated_subset_spec.rb +8 -8
  32. data/spec/operators/random_guess_spec.rb +16 -11
  33. data/spec/operators/resample_and_clone_spec.rb +8 -8
  34. data/spec/operators/uniformBackboneCrossover_spec.rb +7 -7
  35. data/spec/spec_helper.rb +1 -0
  36. metadata +38 -12
  37. data/lib/operators/basic_operators.rb +0 -240
  38. data/lib/operators/samplers_and_selectors.rb +0 -131
data/Rakefile CHANGED
@@ -15,6 +15,7 @@ begin
15
15
  gemspec.add_dependency('nudge', '>= 0.2')
16
16
  gemspec.add_dependency('thor', '>= 0.13')
17
17
  gemspec.add_dependency('couchrest', '>= 0.33')
18
+ gemspec.add_dependency('configatron', '>= 2.6.2')
18
19
  gemspec.add_dependency('fakeweb', '>= 0.33')
19
20
  gemspec.add_dependency('sinatra', '>= 0.9.4')
20
21
  gemspec.add_dependency('activesupport', '>= 2.3.5')
data/Thorfile CHANGED
@@ -33,25 +33,28 @@ class New_Nudge_Type < Thor::Group
33
33
 
34
34
  def create_lib_file
35
35
  filename = "#{camelcased_type_name}.rb"
36
- template("#{nudge_gem_path}/templates/nudge_type_class.erb", "#{New_Nudge_Type.source_root}/lib/nudge/types/#{filename}")
36
+ template("#{nudge_gem_path}/templates/nudge_type_class.erb",
37
+ "#{New_Nudge_Type.source_root}/lib/nudge/types/#{filename}")
37
38
  end
38
-
39
+
39
40
  def create_lib_spec
40
41
  filename = "#{camelcased_type_name}_spec.rb"
41
- template("#{nudge_gem_path}/templates/nudge_type_spec.erb", "#{New_Nudge_Type.source_root}/spec/#{filename}")
42
+ template("#{nudge_gem_path}/templates/nudge_type_spec.erb",
43
+ "#{New_Nudge_Type.source_root}/spec/#{filename}")
42
44
  end
43
-
45
+
44
46
  def create_instructions
45
47
  suite = ["define", "equal_q", "duplicate", "flush", "pop",
46
48
  "random", "rotate", "shove", "swap", "yank", "yankdup"]
47
-
49
+
48
50
  suite.each do |inst|
49
51
  @core = "#{typename_root}_#{inst}"
50
52
  filename = "#{@core}.rb"
51
53
  @instname = "#{@core.camelize}Instruction"
52
54
  @type = typename_root
53
55
  @camelized_type = New_Nudge_Type.type_name(typename_root)
54
- template("#{nudge_gem_path}/templates/nudge_#{inst}_instruction.erb", "#{New_Nudge_Type.source_root}/lib/nudge/instructions/#{filename}")
56
+ template("#{nudge_gem_path}/templates/nudge_#{inst}_instruction.erb",
57
+ "#{New_Nudge_Type.source_root}/lib/nudge/instructions/#{filename}")
55
58
  end
56
59
  end
57
60
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.9
1
+ 0.0.10
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{answer-factory}
8
- s.version = "0.0.9"
8
+ s.version = "0.0.10"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bill Tozier", "Trek Glowacki", "Jesse Sielaff"]
12
- s.date = %q{2010-05-02}
12
+ s.date = %q{2010-05-06}
13
13
  s.default_executable = %q{answer-factory}
14
14
  s.description = %q{The pragmaticgp gem provides a simple framework for building, running and managing genetic programming experiments which automatically discover algorithms and equations to solve user-defined problems.}
15
15
  s.email = %q{bill@vagueinnovation.com}
@@ -32,9 +32,21 @@ Gem::Specification.new do |s|
32
32
  "lib/answers/batch.rb",
33
33
  "lib/factories/factory.rb",
34
34
  "lib/factories/workstation.rb",
35
- "lib/operators/basic_operators.rb",
36
- "lib/operators/evaluators.rb",
37
- "lib/operators/samplers_and_selectors.rb",
35
+ "lib/operators/all_duplicated_genomes_sampler.rb",
36
+ "lib/operators/any_one_sampler.rb",
37
+ "lib/operators/dominated_quantile_selector.rb",
38
+ "lib/operators/infrastructure.rb",
39
+ "lib/operators/most_dominated_subset_sampler.rb",
40
+ "lib/operators/nondominated_subset_selector.rb",
41
+ "lib/operators/point_crossover_operator.rb",
42
+ "lib/operators/point_delete_operator.rb",
43
+ "lib/operators/point_mutation_operator.rb",
44
+ "lib/operators/program_point_count_evaluator.rb",
45
+ "lib/operators/random_guess_operator.rb",
46
+ "lib/operators/resample_and_clone_operator.rb",
47
+ "lib/operators/resample_values_operator.rb",
48
+ "lib/operators/test_case_evaluator.rb",
49
+ "lib/operators/uniform_backbone_crossover_operator.rb",
38
50
  "pkg/nudgegp-0.0.1.gem",
39
51
  "readme.md",
40
52
  "spec/answer_spec.rb",
@@ -102,6 +114,7 @@ Gem::Specification.new do |s|
102
114
  s.add_runtime_dependency(%q<nudge>, [">= 0.2"])
103
115
  s.add_runtime_dependency(%q<thor>, [">= 0.13"])
104
116
  s.add_runtime_dependency(%q<couchrest>, [">= 0.33"])
117
+ s.add_runtime_dependency(%q<configatron>, [">= 2.6.2"])
105
118
  s.add_runtime_dependency(%q<fakeweb>, [">= 0.33"])
106
119
  s.add_runtime_dependency(%q<sinatra>, [">= 0.9.4"])
107
120
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
@@ -109,6 +122,7 @@ Gem::Specification.new do |s|
109
122
  s.add_dependency(%q<nudge>, [">= 0.2"])
110
123
  s.add_dependency(%q<thor>, [">= 0.13"])
111
124
  s.add_dependency(%q<couchrest>, [">= 0.33"])
125
+ s.add_dependency(%q<configatron>, [">= 2.6.2"])
112
126
  s.add_dependency(%q<fakeweb>, [">= 0.33"])
113
127
  s.add_dependency(%q<sinatra>, [">= 0.9.4"])
114
128
  s.add_dependency(%q<activesupport>, [">= 2.3.5"])
@@ -117,6 +131,7 @@ Gem::Specification.new do |s|
117
131
  s.add_dependency(%q<nudge>, [">= 0.2"])
118
132
  s.add_dependency(%q<thor>, [">= 0.13"])
119
133
  s.add_dependency(%q<couchrest>, [">= 0.33"])
134
+ s.add_dependency(%q<configatron>, [">= 2.6.2"])
120
135
  s.add_dependency(%q<fakeweb>, [">= 0.33"])
121
136
  s.add_dependency(%q<sinatra>, [">= 0.9.4"])
122
137
  s.add_dependency(%q<activesupport>, [">= 2.3.5"])
@@ -8,9 +8,21 @@ require 'couchrest'
8
8
  require 'answers/answer'
9
9
  require 'answers/batch'
10
10
 
11
- require 'operators/basic_operators'
11
+ require 'operators/infrastructure'
12
+ require 'operators/random_guess_operator'
13
+ require 'operators/resample_and_clone_operator'
14
+ require 'operators/resample_values_operator'
15
+ require 'operators/uniform_backbone_crossover_operator'
16
+ require 'operators/point_crossover_operator'
17
+ require 'operators/point_delete_operator'
18
+ require 'operators/point_mutation_operator'
19
+
20
+ require 'operators/test_case_evaluator'
21
+ require 'operators/program_point_count_evaluator'
22
+
23
+
24
+
12
25
  require 'operators/samplers_and_selectors'
13
- require 'operators/evaluators'
14
26
 
15
27
  require 'factories/factory'
16
28
  require 'factories/workstation'
@@ -4,7 +4,7 @@ module AnswerFactory
4
4
  class Answer
5
5
  attr_accessor :scores, :tags
6
6
  attr_reader :draft_blueprint, :program, :timestamp, :ancestors
7
- attr_reader :initialization_options, :progress
7
+ attr_reader :initialization_options, :progress, :couch_id
8
8
 
9
9
 
10
10
  def initialize(blueprint, options = {})
@@ -12,11 +12,12 @@ module AnswerFactory
12
12
  blueprint.kind_of?(String) || blueprint.kind_of?(NudgeProgram)
13
13
  build_from_blueprint!(blueprint)
14
14
 
15
- @scores = Hash.new do |hash, key|
15
+ @scores = options[:scores] || Hash.new do |hash, key|
16
16
  raise ArgumentError, "scores must use symbols as keys" unless key.kind_of?(Symbol)
17
17
  nil
18
18
  end
19
19
  @timestamp = Time.now
20
+ @couch_id = options[:couch_id] || ""
20
21
  @initialization_options = options
21
22
  @progress = options[:progress] || 0
22
23
  @ancestors = options[:ancestors] || []
@@ -121,6 +122,19 @@ module AnswerFactory
121
122
 
122
123
 
123
124
  def data
124
- {'blueprint' => self.blueprint, 'tags' => self.tags, 'scores' => self.scores, 'timestamp' => @timestamp}
125
+ {'blueprint' => self.blueprint, 'tags' => self.tags, 'scores' => self.scores, 'progress' => @progress, 'timestamp' => @timestamp}
126
+ end
127
+
128
+
129
+ def from_serial_hash(hash)
130
+ value_hash = hash["value"]
131
+ tag_set = Set.new(value_hash["tags"].collect {|t| t.to_sym})
132
+ symbolized_scores = value_hash["scores"].inject({}) {|memo,(k,v)| memo[k.to_sym] = v; memo }
133
+
134
+ Answer.new(value_hash["blueprint"],
135
+ couch_id:value_hash["_id"],
136
+ tags:tag_set,
137
+ scores:symbolized_scores,
138
+ progress:value_hash["progress"])
125
139
  end
126
140
  end
data/lib/answers/batch.rb CHANGED
@@ -34,11 +34,23 @@ module AnswerFactory
34
34
  end
35
35
 
36
36
 
37
- def self.load_tagged_answers(couchdb_uri, tag)
37
+ def self.load_from_couch(couchdb_uri, design_doc)
38
38
  raise ArgumentError, "#{couchdb_uri} is not a String" unless couchdb_uri.kind_of?(String)
39
- raise ArgumentError, "#{tag} is not a String" unless tag.kind_of?(String)
39
+ raise ArgumentError, "#{design_doc} is not a String" unless design_doc.kind_of?(String)
40
+
41
+ batch = Batch.new
42
+
40
43
  db = CouchRest.database(couchdb_uri) # add the view document and key here
41
- return Batch.new
44
+ begin
45
+ response = db.view(design_doc)
46
+ response["rows"].each do |hash|
47
+ puts hash["values"]
48
+ batch << Answer.from_serial_hash(hash)
49
+ end
50
+ rescue JSON::ParserError => e
51
+ puts "Batch not read due to JSON ParserError: '#{e.message}'"
52
+ end
53
+ return batch
42
54
  end
43
55
 
44
56
 
@@ -1,8 +1,10 @@
1
1
  module AnswerFactory
2
+
2
3
  class Workstation
3
4
  attr_reader :name, :capacity, :couchdb_uri, :factory_name
4
5
  attr_accessor :downstream_stations
5
6
  attr_accessor :answers
7
+ attr_accessor :build_sequence
6
8
 
7
9
 
8
10
  def initialize(name, options = {})
@@ -11,8 +13,9 @@ module AnswerFactory
11
13
  @factory_name = options[:factory_name] || 'factory_name'
12
14
  @couchdb_uri = options[:couchdb_uri] || "http://127.0.0.1:5984/#{@factory_name}"
13
15
  @capacity = options[:capacity] || 100
16
+ @build_sequence = options[:build_sequence] || Array.new
14
17
  @downstream_stations = Array.new
15
- @answers = Array.new
18
+ @answers = Batch.new
16
19
  end
17
20
 
18
21
 
@@ -23,6 +26,52 @@ module AnswerFactory
23
26
  end
24
27
 
25
28
 
29
+ def gather_mine
30
+ @answers += Batch.load_from_couch(@couchdb_uri, "#{name}/current")
31
+ end
32
+
33
+
34
+ def build!
35
+ # Workstation is a superclass; the default behavior (doing nothing)
36
+ # should be overridden in a subclass definition
37
+ end
38
+
39
+
40
+ def process_with(operator)
41
+ raise ArgumentError, "Workstation#process_with cannot process with a #{operator.class}" unless
42
+ operator.kind_of?(SearchOperator)
43
+ operator.generate(@answers)
44
+ end
45
+
46
+
47
+ def ship!
48
+ # Workstation is a superclass; the default behavior (doing nothing)
49
+ # should be overridden in a subclass definition
50
+ end
51
+
52
+
53
+ def ship_to(where, &filter)
54
+ raise ArgumentError, "Workstation#ship_to cannot ship to a #{where.class}" unless
55
+ where.kind_of?(Symbol)
56
+ (@answers.find_all &filter).each {|a| a.add_tag where; a.remove_tag @name}
57
+ end
58
+
59
+
60
+ def scrap!
61
+ # Workstation is a superclass; the default behavior (doing nothing)
62
+ # should be overridden in a subclass definition
63
+ end
64
+
65
+
66
+ def scrap_if(why, &filter)
67
+ (@answers.find_all &filter).each {|a| a.add_tag :SCRAP; a.remove_tag @name}
68
+ end
69
+
70
+ def scrap_everything
71
+ scrap_if("everything dies") {|x| true}
72
+ end
73
+
74
+
26
75
  def cycle
27
76
  self.receive!
28
77
  self.build!
@@ -0,0 +1,14 @@
1
+ module AnswerFactory
2
+ class AllDuplicatedGenomesSampler < Sampler
3
+ def generate(crowd)
4
+ result = Batch.new
5
+ clustered = diversity_classes(crowd)
6
+ clustered.each do |blueprint, array|
7
+ if array.length > 1
8
+ result.concat array
9
+ end
10
+ end
11
+ return result
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module AnswerFactory
2
+ class AnyOneSampler < Sampler
3
+ def generate(crowd)
4
+ result = Batch[crowd.sample]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module AnswerFactory
2
+ class DominatedQuantileSampler < Sampler
3
+ def generate(crowd, proportion = 0.5, template = all_shared_scores(crowd))
4
+ classified = domination_classes(crowd, template)
5
+ increasing_grades = classified.keys.sort {|a,b| b <=> a}
6
+ partial_ordering = []
7
+ increasing_grades.each {|grade| partial_ordering += classified[grade]}
8
+ how_many = (crowd.length * proportion).ceil
9
+
10
+ result = Batch.new
11
+ partial_ordering[0...how_many].each {|dude| result << dude} unless how_many == 0
12
+ return result
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,74 @@
1
+ module AnswerFactory
2
+
3
+ # Abstract class that from which specific SearchOperator subclasses inherit initialization
4
+
5
+ class SearchOperator
6
+ attr_accessor :incoming_options
7
+
8
+ def initialize(options={})
9
+ @incoming_options = options
10
+ end
11
+ end
12
+
13
+
14
+ class Evaluator < SearchOperator
15
+ attr_accessor :score_label
16
+
17
+ def initialize(params = {})
18
+ raise(ArgumentError, "Evaluators must have a score_label") if params[:score_label] == nil
19
+ @score_label = params[:score_label]
20
+ end
21
+ end
22
+
23
+
24
+ class Sampler < SearchOperator
25
+ def initialize (params = {})
26
+ super
27
+ end
28
+
29
+ def all_known_criteria(crowd)
30
+ union = []
31
+ crowd.each do |dude|
32
+ union |= dude.known_criteria
33
+ end
34
+ return union
35
+ end
36
+
37
+
38
+ def all_shared_scores(crowd)
39
+ intersection = self.all_known_criteria(crowd)
40
+ crowd.each do |dude|
41
+ intersection = intersection & dude.known_criteria
42
+ end
43
+ return intersection
44
+ end
45
+
46
+
47
+ def domination_classes(crowd, template = all_shared_scores(crowd))
48
+ result = Hash.new()
49
+
50
+ crowd.each_index do |i|
51
+ dominated_by = 0
52
+
53
+ crowd.each_index do |j|
54
+ dominated_by += 1 if crowd[i].dominated_by?(crowd[j], template)
55
+ end
56
+
57
+ result[dominated_by] ||= []
58
+ result[dominated_by].push crowd[i]
59
+ end
60
+
61
+ return result
62
+ end
63
+
64
+
65
+ def diversity_classes(crowd)
66
+ result = Hash.new()
67
+ crowd.each do |dude|
68
+ result[dude.program.tidy] ||= []
69
+ result[dude.program.tidy] << dude
70
+ end
71
+ return result
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,13 @@
1
+ module AnswerFactory
2
+
3
+ class MostDominatedSubsetSampler < Sampler
4
+ def generate(crowd, template = all_shared_scores(crowd))
5
+ result = Batch.new
6
+ classified = domination_classes(crowd, template)
7
+ worst_key = classified.keys.sort[-1]
8
+ classified[worst_key].each {|bad_dude| result.push bad_dude}
9
+ return result
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,17 @@
1
+ module AnswerFactory
2
+ class NondominatedSubsetSelector < Sampler
3
+
4
+ def generate(crowd, template = all_shared_scores(crowd))
5
+ result = Batch.new
6
+ crowd.each do |answer|
7
+ dominated = false
8
+ crowd.each do |other_answer|
9
+ dominated ||= answer.dominated_by?(other_answer, template)
10
+ end
11
+ result << answer unless dominated
12
+ end
13
+ return result
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,24 @@
1
+ module AnswerFactory
2
+ class PointCrossoverOperator < SearchOperator
3
+ def generate(crowd, howManyBabies = 1)
4
+ raise(ArgumentError) if !crowd.kind_of?(Array)
5
+ raise(ArgumentError) if crowd.empty?
6
+ crowd.each {|dude| raise(ArgumentError) if !dude.kind_of?(Answer) }
7
+
8
+ result = Batch.new
9
+ production = crowd.length*howManyBabies
10
+ production.times do
11
+ mom = crowd.sample
12
+ dad = crowd.sample
13
+ mom_receives = rand(mom.points) + 1
14
+ dad_donates = rand(dad.points) + 1
15
+
16
+ baby_blueprint = mom.replace_point_or_clone(mom_receives,dad.program[dad_donates])
17
+ baby = Answer.new(baby_blueprint,
18
+ progress:[mom.progress,dad.progress].max + 1)
19
+ result << baby
20
+ end
21
+ return result
22
+ end
23
+ end
24
+ end