nudge 0.0.1 → 0.0.2
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.
- data/.gitignore +2 -0
- data/Rakefile +8 -6
- data/VERSION +1 -1
- data/_spikes/nudge3_syntax_spike.txt +23 -0
- data/app_generators/nudge/USAGE +5 -0
- data/app_generators/nudge/nudge_generator.rb +73 -0
- data/app_generators/nudge/templates/activate.rb +0 -0
- data/bin/nudge +17 -0
- data/lib/interpreter/interpreter.rb +6 -3
- data/lib/interpreter/programPoints.rb +2 -2
- data/lib/interpreter/types/codeType.rb +82 -79
- data/lib/interpreter/types/pushTypes.rb +87 -74
- data/lib/nudge.rb +3 -1
- data/lib/search/individual/individual.rb +1 -3
- data/nudge.gemspec +706 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/interpreter/codetype_spec.rb +0 -5
- data/spec/interpreter/erc_spec.rb +2 -2
- data/spec/interpreter/interpreter_spec.rb +1 -1
- data/spec/interpreter/literal_spec.rb +1 -1
- data/spec/interpreter/treetophelpers.rb +27 -0
- data/spec/interpreter/types_spec.rb +30 -10
- data/spec/spec_helper.rb +5 -1
- data/test/test_generator_helper.rb +29 -0
- data/test/test_nudge_generator.rb +43 -0
- metadata +28 -13
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -5,16 +5,18 @@ begin
|
|
5
5
|
Jeweler::Tasks.new do |gemspec|
|
6
6
|
gemspec.name = "nudge"
|
7
7
|
gemspec.summary = "Genetic Programming in the Nudge language"
|
8
|
-
gemspec.description = "It
|
8
|
+
gemspec.description = "DOES NOT WORK YET. The nudge gem will provide a simple framework for building, running and managing genetic programming experiments which automatically discover algorithms and equations to solve well-defined target problems. It depends on CouchDB and Ruby 1.9+"
|
9
9
|
gemspec.email = "bill@vagueinnovation.com"
|
10
10
|
gemspec.homepage = "http://github.com/Vaguery/PragGP"
|
11
11
|
gemspec.authors = ["Bill Tozier", "Trek Glowacki"]
|
12
12
|
|
13
|
-
gemspec.
|
14
|
-
|
15
|
-
gemspec.add_dependency('
|
16
|
-
gemspec.add_dependency('
|
17
|
-
gemspec.add_dependency('
|
13
|
+
gemspec.required_ruby_version = '>= 1.9.1'
|
14
|
+
|
15
|
+
gemspec.add_dependency('couchrest', '>= 0.33')
|
16
|
+
gemspec.add_dependency('sinatra', '>= 0.9.4')
|
17
|
+
gemspec.add_dependency('treetop', '>= 1.4.3')
|
18
|
+
gemspec.add_dependency('polyglot', '>= 0.2.9')
|
19
|
+
gemspec.add_dependency('activesupport', '>= 2.3.5')
|
18
20
|
end
|
19
21
|
|
20
22
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -0,0 +1,23 @@
|
|
1
|
+
NUDGECODE:
|
2
|
+
|
3
|
+
block {
|
4
|
+
literal «1»
|
5
|
+
literal «2»
|
6
|
+
block {
|
7
|
+
sample «3»
|
8
|
+
sample «4»
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
# local values:
|
13
|
+
«1» float: 9.128
|
14
|
+
«2» code: block {literal code «5» block {sample bool «6»}}
|
15
|
+
«3» image: file:///881727183.jpg
|
16
|
+
«4» int: 881
|
17
|
+
«5» code: block { do int_add do int_multiply }
|
18
|
+
«6» bool: false
|
19
|
+
|
20
|
+
# local values can include references to other local values, but can never backtrack
|
21
|
+
# syntax check: are all local values assigned?
|
22
|
+
# syntax check: are all local values strings?
|
23
|
+
# semantic check: are there no backward-references?
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class NudgeGenerator < RubiGen::Base
|
2
|
+
|
3
|
+
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
4
|
+
Config::CONFIG['ruby_install_name'])
|
5
|
+
|
6
|
+
default_options :author => nil
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
def initialize(runtime_args, runtime_options = {})
|
11
|
+
super
|
12
|
+
usage if args.empty?
|
13
|
+
@destination_root = File.expand_path(args.shift)
|
14
|
+
@name = base_name
|
15
|
+
extract_options
|
16
|
+
end
|
17
|
+
|
18
|
+
def manifest
|
19
|
+
record do |m|
|
20
|
+
# Ensure appropriate folder(s) exists
|
21
|
+
m.directory ''
|
22
|
+
BASEDIRS.each { |path| m.directory path }
|
23
|
+
|
24
|
+
# Create stubs
|
25
|
+
# m.template "template.rb", "some_file_after_erb.rb"
|
26
|
+
# m.template_copy_each ["template.rb", "template2.rb"]
|
27
|
+
# m.file "file", "some_file_copied"
|
28
|
+
|
29
|
+
m.file "activate.rb", "activate.rb"
|
30
|
+
|
31
|
+
# m.file_copy_each ["path/to/file", "path/to/file2"]
|
32
|
+
|
33
|
+
m.dependency "install_rubigen_scripts", [destination_root, 'nudge'],
|
34
|
+
:shebang => options[:shebang], :collision => :force
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
def banner
|
40
|
+
<<-EOS
|
41
|
+
Creates a ...
|
42
|
+
|
43
|
+
USAGE: #{spec.name} name
|
44
|
+
EOS
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_options!(opts)
|
48
|
+
opts.separator ''
|
49
|
+
opts.separator 'Options:'
|
50
|
+
# For each option below, place the default
|
51
|
+
# at the top of the file next to "default_options"
|
52
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
53
|
+
# "Some comment about this option",
|
54
|
+
# "Default: none") { |o| options[:author] = o }
|
55
|
+
opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_options
|
59
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
60
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
61
|
+
# raw instance variable value.
|
62
|
+
# @author = options[:author]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Installation skeleton. Intermediate directories are automatically
|
66
|
+
# created so don't sweat their absence here.
|
67
|
+
BASEDIRS = %w(
|
68
|
+
config
|
69
|
+
experiment
|
70
|
+
spec
|
71
|
+
tmp
|
72
|
+
)
|
73
|
+
end
|
File without changes
|
data/bin/nudge
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rubigen'
|
5
|
+
|
6
|
+
if %w(-v --version).include? ARGV.first
|
7
|
+
require 'nudge/version'
|
8
|
+
puts "#{File.basename($0)} #{Nudge::VERSION}"
|
9
|
+
exit(0)
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rubigen/scripts/generate'
|
13
|
+
source = RubiGen::PathSource.new(:application,
|
14
|
+
File.join(File.dirname(__FILE__), "../app_generators"))
|
15
|
+
RubiGen::Base.reset_sources
|
16
|
+
RubiGen::Base.append_sources source
|
17
|
+
RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'nudge')
|
@@ -101,15 +101,18 @@ module Nudge
|
|
101
101
|
def enable(item)
|
102
102
|
if item.superclass == Instruction
|
103
103
|
@instructions_library[item] = item.new(self)
|
104
|
-
elsif item.
|
104
|
+
elsif item.include? NudgeType
|
105
105
|
@types |= [item]
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
109
|
def active?(item)
|
110
|
+
puts "#{item.inspect} is the item"
|
110
111
|
if item.superclass == Instruction
|
111
112
|
@instructions_library.include?(item)
|
112
|
-
elsif item.
|
113
|
+
elsif item.include? NudgeType
|
114
|
+
puts "#{@types} is the type list"
|
115
|
+
|
113
116
|
@types.include?(item)
|
114
117
|
end
|
115
118
|
end
|
@@ -160,7 +163,7 @@ module Nudge
|
|
160
163
|
def disable(item)
|
161
164
|
if item.superclass == Instruction
|
162
165
|
@instructions_library.delete(item)
|
163
|
-
elsif item.
|
166
|
+
elsif item.include? NudgeType
|
164
167
|
@types.delete(item)
|
165
168
|
end
|
166
169
|
end
|
@@ -82,7 +82,7 @@ module Nudge
|
|
82
82
|
def randomize(context)
|
83
83
|
raise(ArgumentError,"Random code cannot be created") if context.types == [CodeType]
|
84
84
|
newType = context.types.sample
|
85
|
-
@type = newType.
|
85
|
+
@type = newType.to_nudgecode
|
86
86
|
if newType != CodeType
|
87
87
|
@value = newType.any_value
|
88
88
|
else
|
@@ -123,7 +123,7 @@ module Nudge
|
|
123
123
|
|
124
124
|
def randomize(context)
|
125
125
|
newType = context.types.sample
|
126
|
-
@type = newType.
|
126
|
+
@type = newType.to_nudgecode
|
127
127
|
if newType != CodeType
|
128
128
|
@value = newType.any_value
|
129
129
|
else
|
@@ -1,108 +1,111 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
|
3
|
-
class CodeType < NudgeType
|
4
|
-
@@defaultPoints = 20
|
2
|
+
module NudgeType
|
5
3
|
|
6
|
-
|
7
|
-
|
4
|
+
class CodeType
|
5
|
+
include TypeBehaviors
|
6
|
+
@@defaultPoints = 20
|
7
|
+
|
8
|
+
def self.random_skeleton(points=@@defaultPoints, blocks=points/10)
|
9
|
+
blocks = [0,[points,blocks].min].max
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
if points > 1
|
12
|
+
skel = ["block {"]
|
13
|
+
(points-2).times {skel << "*"}
|
14
|
+
skel << "*}"
|
15
|
+
front = 0
|
16
|
+
(blocks-1).times do
|
17
|
+
until skel[front].include?("*") do
|
18
|
+
a,b = rand(points), rand(points)
|
19
|
+
front,back = [a,b].min, [a,b].max
|
20
|
+
end
|
21
|
+
skel[front] = skel[front].sub(/\*/," block {")
|
22
|
+
skel[back] = skel[back] + "}"
|
18
23
|
end
|
19
|
-
skel
|
20
|
-
skel[back] = skel[back] + "}"
|
21
|
-
end
|
22
|
-
skel = skel.join
|
23
|
-
else
|
24
|
-
if blocks>0
|
25
|
-
skel = "block {}"
|
24
|
+
skel = skel.join
|
26
25
|
else
|
27
|
-
|
26
|
+
if blocks>0
|
27
|
+
skel = "block {}"
|
28
|
+
else
|
29
|
+
skel = "*"
|
30
|
+
end
|
28
31
|
end
|
32
|
+
return skel
|
29
33
|
end
|
30
|
-
return skel
|
31
|
-
end
|
32
34
|
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
def self.any_type(types)
|
37
|
+
raise(ArgumentError,"no available NudgeTypes") if types.empty?
|
38
|
+
return types.sample
|
39
|
+
end
|
38
40
|
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
def self.any_instruction(instructions)
|
43
|
+
raise(ArgumentError,"no available Instructions") if instructions.empty?
|
44
|
+
return instructions.sample
|
45
|
+
end
|
44
46
|
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def self.any_reference(references)
|
49
|
+
raise(ArgumentError,"no available references") if references.empty?
|
50
|
+
return references.sample
|
51
|
+
end
|
50
52
|
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
def self.roulette_wheel(references, instructions, types)
|
55
|
+
basis = Hash["reference", references.length,
|
56
|
+
"instruction", instructions.length,
|
57
|
+
"sample", types.length]
|
58
|
+
sum = basis.values.inject(:+)
|
59
|
+
spin = rand(sum)
|
60
|
+
basis.each do |result,weight|
|
61
|
+
return result if spin <= weight && weight > 0
|
62
|
+
spin -= weight
|
63
|
+
end
|
64
|
+
raise "A problem occurred when executing CodeType#roulette_wheel"
|
61
65
|
end
|
62
|
-
raise "A problem occurred when executing CodeType#roulette_wheel"
|
63
|
-
end
|
64
66
|
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
68
|
+
def self.random_value(context, params = {})
|
69
|
+
points = params[:points] || @@defaultPoints
|
70
|
+
blocks = params[:blocks] || points/10
|
71
|
+
skeleton = params[:skeleton] || self.random_skeleton(points, blocks)
|
72
|
+
instructions = params[:instructions] || context.instructions
|
73
|
+
references = params[:references] || context.references
|
74
|
+
types = params[:types] || context.types
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
76
|
+
while skeleton.include?("*") do
|
77
|
+
case self.roulette_wheel(references,instructions,types)
|
78
|
+
when "instruction"
|
79
|
+
newPoint = " do " + self.any_instruction(instructions).to_nudgecode
|
80
|
+
when "reference"
|
81
|
+
newPoint = " ref " + self.any_reference(references)
|
82
|
+
when "sample"
|
83
|
+
theType = any_type(types)
|
84
|
+
if theType == CodeType
|
85
|
+
if types != [CodeType]
|
86
|
+
theType = self.any_type(types - [CodeType])
|
87
|
+
else
|
88
|
+
raise ArgumentError, "Random code cannot be created"
|
89
|
+
end
|
87
90
|
end
|
91
|
+
newPoint = " sample " + theType.to_nudgecode + " (" + theType.any_value.to_s + ")"
|
92
|
+
else
|
93
|
+
raise ArgumentError, "Nothing to make random code from"
|
88
94
|
end
|
89
|
-
|
90
|
-
|
91
|
-
raise ArgumentError, "Nothing to make random code from"
|
95
|
+
skeleton = skeleton.sub(/\*/, newPoint)
|
96
|
+
skeleton = skeleton.sub(/\n/,'')
|
92
97
|
end
|
93
|
-
skeleton
|
94
|
-
skeleton = skeleton.sub(/\n/,'')
|
98
|
+
skeleton
|
95
99
|
end
|
96
|
-
skeleton
|
97
|
-
end
|
98
100
|
|
99
101
|
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
-
|
103
|
+
def self.from_s(string_value)
|
104
|
+
return string_value.sub(/\(/,"«").sub(/\)/,"»")
|
105
|
+
end
|
104
106
|
|
105
|
-
|
106
|
-
|
107
|
+
def self.any_value(context)
|
108
|
+
self.random_value(context)
|
109
|
+
end
|
107
110
|
end
|
108
111
|
end
|
@@ -1,102 +1,115 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
require 'singleton'
|
5
|
-
include Singleton
|
6
|
-
|
7
|
-
@@all_types = []
|
8
|
-
|
9
|
-
def self.inherited(subclass)
|
10
|
-
@@all_types << subclass
|
11
|
-
super
|
12
|
-
end
|
3
|
+
module NudgeType
|
13
4
|
|
14
5
|
def self.all_types
|
15
|
-
|
6
|
+
@all_types ||= []
|
16
7
|
end
|
17
8
|
|
18
9
|
def self.push_types
|
19
10
|
[IntType, BoolType, FloatType]
|
20
11
|
end
|
21
12
|
|
22
|
-
|
23
|
-
self.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
13
|
+
module TypeBehaviors
|
14
|
+
def self.extended(subclass)
|
15
|
+
NudgeType.all_types << subclass
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_nudgecode
|
19
|
+
self.to_s.demodulize.slice(0..-5).downcase.intern
|
20
|
+
end
|
31
21
|
|
22
|
+
def from_s(some_string)
|
23
|
+
raise "This class must implement #{self.inspect}.from_s"
|
24
|
+
end
|
32
25
|
|
26
|
+
def any_value
|
27
|
+
raise "This class must implement #{self.inspect}.any_value"
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
def self.defaultLowest
|
39
|
-
@defaultLowest
|
30
|
+
def random_value(params)
|
31
|
+
raise "This class must implement #{self.inspect}.random_value"
|
32
|
+
end
|
40
33
|
end
|
41
34
|
|
42
|
-
|
43
|
-
|
35
|
+
class BasicType
|
36
|
+
def self.inherited(subclass)
|
37
|
+
subclass.extend TypeBehaviors
|
38
|
+
end
|
44
39
|
end
|
45
40
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
rand(highest-lowest).to_i + lowest
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.from_s(string_value)
|
54
|
-
return string_value.to_i
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.any_value
|
58
|
-
self.random_value
|
59
|
-
end
|
60
|
-
end
|
41
|
+
class IntType < Fixnum
|
42
|
+
extend TypeBehaviors
|
43
|
+
@defaultLowest = -100
|
44
|
+
@defaultHighest = 100
|
61
45
|
|
46
|
+
def self.defaultLowest
|
47
|
+
@defaultLowest
|
48
|
+
end
|
62
49
|
|
50
|
+
def self.defaultHighest
|
51
|
+
@defaultHighest
|
52
|
+
end
|
63
53
|
|
54
|
+
def self.random_value(params={})
|
55
|
+
bottom = params[:randomIntegerLowerBound] || @defaultLowest
|
56
|
+
top = params[:randomIntegerUpperBound] || @defaultHighest
|
57
|
+
lowest, highest = [bottom,top].min, [bottom,top].max
|
58
|
+
rand(highest-lowest).to_i + lowest
|
59
|
+
end
|
64
60
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
return string_value.downcase == "true"
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.any_value
|
76
|
-
self.random_value
|
61
|
+
def self.from_s(string_value)
|
62
|
+
return string_value.to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.any_value
|
66
|
+
self.random_value
|
67
|
+
end
|
77
68
|
end
|
78
|
-
end
|
79
69
|
|
80
70
|
|
81
71
|
|
82
72
|
|
83
|
-
class
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
73
|
+
class BoolType
|
74
|
+
extend TypeBehaviors
|
75
|
+
|
76
|
+
def self.random_value(params = {})
|
77
|
+
p = params[:randomBooleanTruthProb] || 0.5
|
78
|
+
rand() < p
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.from_s(string_value)
|
82
|
+
string_value.downcase == "true" ? true : false
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.any_value
|
86
|
+
self.random_value
|
87
|
+
end
|
97
88
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
class FloatType < Float
|
94
|
+
extend TypeBehaviors
|
95
|
+
|
96
|
+
@defaultLowest = -1000.0
|
97
|
+
@defaultHighest = 1000.0
|
98
|
+
|
99
|
+
def self.random_value(params = {})
|
100
|
+
bottom = params[:randomFloatLowerBound] || @defaultLowest
|
101
|
+
top = params[:randomFloatUpperBound] || @defaultHighest
|
102
|
+
bottom, top = [bottom,top].min, [bottom,top].max
|
103
|
+
range = top - bottom
|
104
|
+
(rand*range) + bottom
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.from_s(string_value)
|
108
|
+
return string_value.to_f
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.any_value
|
112
|
+
self.random_value
|
113
|
+
end
|
101
114
|
end
|
102
|
-
end
|
115
|
+
end
|
data/lib/nudge.rb
CHANGED
@@ -35,4 +35,6 @@ require 'search/operators/basic_operators'
|
|
35
35
|
require 'search/operators/samplers_and_selectors'
|
36
36
|
require 'search/operators/evaluators'
|
37
37
|
require 'search/stations/station'
|
38
|
-
require 'search/experiments/experiment'
|
38
|
+
require 'search/experiments/experiment'
|
39
|
+
|
40
|
+
include NudgeType
|
@@ -28,9 +28,7 @@ module Nudge
|
|
28
28
|
attr_reader :id
|
29
29
|
|
30
30
|
def initialize(listing)
|
31
|
-
@helperParser =
|
32
|
-
|
33
|
-
@genome = listing
|
31
|
+
@helperParser = @genome = listing
|
34
32
|
raise(ArgumentError, "Nudge program cannot be parsed") if Individual.helperParser.parse(genome) == nil
|
35
33
|
@program = Individual.helperParser.parse(genome).to_points
|
36
34
|
@scores = Hash.new
|