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,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 William Tozier
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "answer-factory"
7
+ gemspec.summary = "Genetic Programming in the Nudge language"
8
+ gemspec.description = "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."
9
+ gemspec.email = "bill@vagueinnovation.com"
10
+ gemspec.homepage = "http://github.com/Vaguery/PragGP"
11
+ gemspec.authors = ["Bill Tozier", "Trek Glowacki", "Jesse Sielaff"]
12
+
13
+ gemspec.required_ruby_version = '>= 1.9.1'
14
+
15
+ gemspec.add_dependency('nudge', '>= 0.2')
16
+ gemspec.add_dependency('thor', '>= 0.13')
17
+ gemspec.add_dependency('couchrest', '>= 0.33')
18
+ gemspec.add_dependency('fakeweb', '>= 0.33')
19
+ gemspec.add_dependency('sinatra', '>= 0.9.4')
20
+ gemspec.add_dependency('activesupport', '>= 2.3.5')
21
+
22
+ #files
23
+ gemspec.files.exclude('_spikes/**')
24
+ end
25
+
26
+ Jeweler::GemcutterTasks.new
27
+ rescue LoadError
28
+ puts "Jeweler not available. Install it with: gem install jeweler"
29
+ end
@@ -0,0 +1,79 @@
1
+ require 'active_support'
2
+ require 'lib/answer-factory'
3
+
4
+ class Extend_Nudge < Thor::Group
5
+ include Thor::Actions
6
+
7
+ # Define arguments and options
8
+ argument :project_name
9
+ class_option :test_framework, :default => :rspec
10
+ desc "Creates a new project folder structure for Nudge types, instructions and specs"
11
+
12
+
13
+ def self.source_root
14
+ File.dirname(__FILE__)
15
+ end
16
+
17
+ def create_project_folder
18
+ dirname = "#{Extend_Nudge.source_root}/#{project_name}"
19
+ puts dirname
20
+ if Dir.exist?(dirname) then
21
+ puts "project directory 'dirname' already exists"
22
+ else
23
+ empty_directory(dirname)
24
+ empty_directory("#{dirname}/lib")
25
+ empty_directory("#{dirname}/lib/instructions")
26
+ empty_directory("#{dirname}/lib/interpreter/types")
27
+ empty_directory("#{dirname}/spec")
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ class New_Nudge_Type < Thor::Group
34
+ include Thor::Actions
35
+
36
+ # Define arguments and options
37
+ argument :typename_root
38
+ class_option :test_framework, :default => :rspec
39
+ desc "Creates a new NudgeType class definition file, typical instructions, and rspec files"
40
+
41
+
42
+ def self.source_root
43
+ File.dirname(__FILE__)
44
+ end
45
+
46
+ def self.type_name(string)
47
+ string.camelize + "Type"
48
+ end
49
+
50
+ def nudge_gem_path
51
+ Nudge.gem_root
52
+ end
53
+
54
+ def create_lib_file
55
+ @camelcased_type_name = New_Nudge_Type.type_name(typename_root)
56
+ filename = "#{@camelcased_type_name}.rb"
57
+ template("#{nudge_gem_path}/templates/nudge_type_class.erb", "#{New_Nudge_Type.source_root}/lib/types/#{filename}")
58
+ end
59
+
60
+ def create_lib_spec
61
+ @camelcased_type_name = New_Nudge_Type.type_name(typename_root)
62
+ filename = "#{@camelcased_type_name}_spec.rb"
63
+ template("#{nudge_gem_path}/templates/nudge_type_spec.erb", "#{New_Nudge_Type.source_root}/spec/#{filename}")
64
+ end
65
+
66
+ def create_instructions
67
+ suite = ["define", "equal_q", "duplicate", "flush", "pop",
68
+ "random", "rotate", "shove", "swap", "yank", "yankdup"]
69
+
70
+ suite.each do |inst|
71
+ @core = "#{typename_root}_#{inst}"
72
+ filename = "#{@core}.rb"
73
+ @instname = "#{@core.camelize}Instruction"
74
+ @type = typename_root
75
+ @camelized_type = New_Nudge_Type.type_name(typename_root)
76
+ template("#{nudge_gem_path}/templates/nudge_#{inst}_instruction.erb", "#{New_Nudge_Type.source_root}/lib/instructions/#{filename}")
77
+ end
78
+ end
79
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,45 @@
1
+ require 'nudge'
2
+ require '../lib/answer-factory'
3
+ include Nudge
4
+ include NudgeGP
5
+
6
+
7
+ d1 = Answer.new("")
8
+ d2 = Answer.new("")
9
+
10
+ t1 = Time.now
11
+ 100000.times do
12
+ d1.scores = {"a" => rand(20)-10, "b" => rand(20)-10,"c" => rand(20)-10,"d" => rand(20)-10,"e" => rand(20)-10,"e1" => rand(20)-10,"e2" => rand(20)-10,"e3" => rand(20)-10,"e4" => rand(20)-10,"e5" => rand(20)-10,"e6" => rand(20)-10,"edfsgdf" => rand(20)-10,"se" => rand(20)-10}
13
+ d2.scores = {"a" => rand(20)-10, "b" => rand(20)-10,"c" => rand(20)-10,"d" => rand(20)-10,"e" => rand(20)-10,"e1" => rand(20)-10,"e2" => rand(20)-10,"e3" => rand(20)-10,"e4" => rand(20)-10,"e5" => rand(20)-10,"e6" => rand(20)-10,"edfsgdf" => rand(20)-10,"se" => rand(20)-10}
14
+ d1.dominated_by?(d2)
15
+ end
16
+ puts "#{Time.now - t1} sec from the new one"
17
+
18
+
19
+ class Answer
20
+ def dominated_by?(other, template = self.known_criteria)
21
+ return false unless (known_criteria == other.known_criteria)
22
+
23
+ noWorse = true
24
+ somewhatBetter = false
25
+ template.each do |score|
26
+ if self.scores[score] && other.scores[score]
27
+ noWorse &&= (self.scores[score] >= other.scores[score])
28
+ somewhatBetter ||= (self.scores[score] > other.scores[score])
29
+ else
30
+ return false
31
+ end
32
+ end
33
+ return noWorse && somewhatBetter
34
+ end
35
+ end
36
+
37
+
38
+ t1 = Time.now
39
+ 100000.times do
40
+ d1.scores = {"a" => rand(20)-10, "b" => rand(20)-10,"c" => rand(20)-10,"d" => rand(20)-10,"e" => rand(20)-10,"e1" => rand(20)-10,"e2" => rand(20)-10,"e3" => rand(20)-10,"e4" => rand(20)-10,"e5" => rand(20)-10,"e6" => rand(20)-10,"edfsgdf" => rand(20)-10,"se" => rand(20)-10}
41
+ d2.scores = {"a" => rand(20)-10, "b" => rand(20)-10,"c" => rand(20)-10,"d" => rand(20)-10,"e" => rand(20)-10,"e1" => rand(20)-10,"e2" => rand(20)-10,"e3" => rand(20)-10,"e4" => rand(20)-10,"e5" => rand(20)-10,"e6" => rand(20)-10,"edfsgdf" => rand(20)-10,"se" => rand(20)-10}
42
+ d1.dominated_by?(d2)
43
+ end
44
+ puts "#{Time.now - t1} sec from the old one"
45
+
@@ -0,0 +1,9 @@
1
+ # realy wants to use CouchDB version 0.11 or higher
2
+
3
+ # edit this to fit your particular CouchDB configuration
4
+ main_database:
5
+ db_root: http://127.0.0.1:5984 # URI of your CouchDB server
6
+ db_name: my_factory # root database handling your AnswerFactory:
7
+ tag_filter: _design/routing/_view/by_tag # don't edit this unless you also
8
+ # change how it's used in the codebase!
9
+
@@ -0,0 +1,14 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../lib")
2
+
3
+ require 'rubygems'
4
+ require 'nudge'
5
+
6
+ require 'answers/answer'
7
+ require 'answers/batch'
8
+
9
+ require 'operators/basic_operators'
10
+ require 'operators/samplers_and_selectors'
11
+ require 'operators/evaluators'
12
+
13
+ require 'factories/factory'
14
+ require 'factories/workstation'
@@ -0,0 +1,126 @@
1
+ require 'set'
2
+
3
+ module NudgeGP
4
+ class Answer
5
+ attr_accessor :scores, :tags
6
+ attr_reader :draft_blueprint, :program, :timestamp, :ancestors
7
+ attr_reader :initialization_options, :progress
8
+
9
+
10
+ def initialize(blueprint, options = {})
11
+ raise ArgumentError unless
12
+ blueprint.kind_of?(String) || blueprint.kind_of?(NudgeProgram)
13
+ build_from_blueprint!(blueprint)
14
+
15
+ @scores = Hash.new do |hash, key|
16
+ raise ArgumentError, "scores must use symbols as keys" unless key.kind_of?(Symbol)
17
+ nil
18
+ end
19
+ @timestamp = Time.now
20
+ @initialization_options = options
21
+ @progress = options[:progress] || 0
22
+ @ancestors = options[:ancestors] || []
23
+ @tags = Set.new(options[:tags]) || Set.new
24
+ end
25
+
26
+
27
+ def build_from_blueprint!(blueprint)
28
+ if blueprint.kind_of?(String)
29
+ @draft_blueprint = blueprint
30
+ @program = NudgeProgram.new(blueprint)
31
+ else
32
+ @program = blueprint
33
+ @draft_blueprint = @program.blueprint
34
+ end
35
+ end
36
+
37
+
38
+ def blueprint
39
+ @program.blueprint
40
+ end
41
+
42
+
43
+ def parses?
44
+ @program.parses?
45
+ end
46
+
47
+
48
+ def known_criteria
49
+ @scores.keys.sort
50
+ end
51
+
52
+
53
+ def score_vector(ordering = known_criteria)
54
+ ordering.collect {|k| @scores[k]}
55
+ end
56
+
57
+
58
+ def dominated_by?(other_answer, comparison_criteria = self.known_criteria)
59
+
60
+ return false unless (known_criteria & comparison_criteria) ==
61
+ (other_answer.known_criteria & comparison_criteria)
62
+
63
+ could_be_identical = true
64
+
65
+ comparison_criteria.each do |score|
66
+ return false if (my_score = self.scores[score]) < (other_score = other_answer.scores[score])
67
+
68
+ if could_be_identical
69
+ could_be_identical &&= (my_score == other_score)
70
+ end
71
+ end
72
+
73
+ return !could_be_identical
74
+ rescue NoMethodError
75
+ false
76
+ end
77
+
78
+
79
+ def points
80
+ @program.points
81
+ end
82
+
83
+
84
+ def delete_point_or_clone(which)
85
+ ((1..self.points).include?(which)) ?
86
+ self.program.delete_point(which) :
87
+ self.program.deep_copy
88
+ end
89
+
90
+
91
+ def replace_point_or_clone(which, object)
92
+ if object.kind_of?(String)
93
+ prog = NudgeProgram.new(object)
94
+ if !prog.parses?
95
+ raise(ArgumentError, "Replacement point cannot be parsed")
96
+ else
97
+ new_point = prog.linked_code
98
+ end
99
+ elsif object.kind_of?(ProgramPoint)
100
+ new_point = object
101
+ else
102
+ raise(ArgumentError, "Program points cannot be replaced by #{object.class} objects")
103
+ end
104
+
105
+ ((1..self.points).include?(which)) ?
106
+ self.program.replace_point(which, new_point) :
107
+ self.program.deep_copy
108
+ end
109
+ end
110
+
111
+
112
+ def add_tag(new_tag)
113
+ raise ArgumentError, "#{new_tag} is not a Symbol" unless new_tag.kind_of?(Symbol)
114
+ @tags.add(new_tag)
115
+ end
116
+
117
+
118
+ def remove_tag(old_tag)
119
+ @tags.delete(old_tag)
120
+ end
121
+
122
+
123
+ def data
124
+ {'blueprint' => self.blueprint, 'tags' => self.tags, 'scores' => self.scores, 'timestamp' => @timestamp}
125
+ end
126
+ end
@@ -0,0 +1,49 @@
1
+ module NudgeGP
2
+ # A Batch is simply an Array of Answers, with validation for all assignment methods
3
+ class Batch < Array
4
+
5
+ def self.[](*args)
6
+ raise ArgumentError unless args.inject(true) {|anded, a| anded & a.kind_of?(Answer)}
7
+ super
8
+ end
9
+
10
+
11
+ def []=(index, obj)
12
+ raise ArgumentError unless obj.kind_of?(Answer)
13
+ super
14
+ end
15
+
16
+
17
+ def <<(obj)
18
+ raise ArgumentError unless obj.kind_of?(Answer)
19
+ super
20
+ end
21
+
22
+
23
+ def initialize(*args)
24
+ raise ArgumentError unless args.inject(true) {|anded, a| anded & a.kind_of?(Answer)}
25
+ super
26
+ end
27
+
28
+
29
+ def bulk_save!(couchdb_uri)
30
+ raise ArgumentError, "#{couchdb_uri} is not a String" unless couchdb_uri.kind_of?(String)
31
+
32
+ db = CouchRest.database!(couchdb_uri)
33
+ db.bulk_save(self.data)
34
+ end
35
+
36
+
37
+ def self.load_tagged_answers(couchdb_uri, tag)
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)
40
+ db = CouchRest.database(couchdb_uri) # add the view document and key here
41
+ return Batch.new
42
+ end
43
+
44
+
45
+ def data
46
+ self.collect {|i| i.data}
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,53 @@
1
+ module NudgeGP
2
+ class Factory
3
+ require 'open-uri'
4
+ require 'configatron'
5
+
6
+ attr_reader :name
7
+ attr_reader :instruction_library, :type_library
8
+ attr_accessor :workstation_names
9
+ attr_reader :original_options_hash
10
+
11
+
12
+ def initialize(name = "my_factory", options = {})
13
+ @name = name
14
+ @original_options_hash = options
15
+ @instruction_library = options[:instruction_library] || Instruction.all_instructions
16
+ @type_library = options[:type_library] || NudgeType.all_types
17
+ @workstation_names = Array.new
18
+
19
+ self.configure!
20
+ end
21
+
22
+
23
+ def couch_available?
24
+ open(self.configatron.couchdb_uri).status
25
+ true
26
+ rescue StandardError
27
+ false
28
+ end
29
+
30
+
31
+ def configure!
32
+ self.configure_constants!
33
+ self.configure_paths!
34
+ self.configure_databases!
35
+ end
36
+
37
+
38
+ def configure_constants!
39
+ self.configatron.factory_name = self.name
40
+ end
41
+
42
+
43
+ def configure_paths!
44
+ self.configatron.factory_root = File.expand_path("#{File.dirname(__FILE__)}/../..")
45
+ end
46
+
47
+
48
+ def configure_databases!
49
+ self.configatron.configure_from_yaml("#{self.configatron.factory_root}/config/database.yml")
50
+ self.configatron.couchdb_uri = "#{self.configatron.main_database.db_root}/#{self.name}"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module NudgeGP
2
+ class Workstation
3
+ attr_reader :name, :capacity, :couchdb_uri, :factory_name
4
+ attr_accessor :downstream_stations
5
+ attr_accessor :answers
6
+
7
+
8
+ def initialize(name, options = {})
9
+ raise ArgumentError, "#{name} is not a Symbol" unless name.kind_of?(Symbol)
10
+ @name = name
11
+ @factory_name = options[:factory_name] || 'factory_name'
12
+ @couchdb_uri = options[:couchdb_uri] || "http://127.0.0.1:5984/#{@factory_name}"
13
+ @capacity = options[:capacity] || 100
14
+ @downstream_stations = Array.new
15
+ @answers = Array.new
16
+ end
17
+
18
+
19
+ def transfer_answer(which, where)
20
+ raise ArgumentError, "#{where} is not a Symbol" unless where.kind_of?(Symbol)
21
+ which.remove_tag(self.name)
22
+ which.add_tag(where)
23
+ end
24
+
25
+
26
+ def cycle
27
+ self.receive!
28
+ self.build!
29
+ self.ship!
30
+ self.scrap!
31
+ end
32
+ end
33
+ end