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