drp 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,67 @@
1
+
2
+ =begin
3
+
4
+ DRP, Genetic Programming + Grammatical Evolution = Directed Ruby Programming
5
+ Copyright (C) 2006, Christophe McKeon
6
+
7
+ This program is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU General Public License
9
+ as published by the Free Software Foundation; either version 2
10
+ of the License, or (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program; if not, write to the Free Softwar Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
+
20
+ =end
21
+
22
+ module DRP
23
+
24
+ module Utils
25
+
26
+ class << self
27
+
28
+ def map range, val, function = :linear
29
+ # this line is necessary in case nil is explicitly passed
30
+ function = function ? function.to_sym : :linear
31
+ case function.to_sym
32
+
33
+ when :linear, :lin
34
+ linear_map range, val
35
+
36
+ when :i_linear, :i_lin
37
+ i_linear_map range, val
38
+
39
+ else
40
+ raise ArgumentError, "bad function for range: #{function}", caller
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def linear_map range, val
47
+ first, last = range.first, range.last
48
+ diff = last - first
49
+ diff * val + first
50
+ end
51
+
52
+ def i_linear_map range, val
53
+ first, last = range.first, range.last
54
+ distance = (last - first).to_i.abs + 1
55
+ i = (distance * val).floor
56
+ if first < last
57
+ first + i
58
+ else
59
+ first - i
60
+ end
61
+ end
62
+
63
+ end # class << self
64
+
65
+ end # module Utils
66
+
67
+ end # module DRP
@@ -0,0 +1,264 @@
1
+
2
+ =begin
3
+
4
+ DRP, Genetic Programming + Grammatical Evolution = Directed Ruby Programming
5
+ Copyright (C) 2006, Christophe McKeon
6
+
7
+ This program is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU General Public License
9
+ as published by the Free Software Foundation; either version 2
10
+ of the License, or (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program; if not, write to the Free Softwar Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
+
20
+ =end
21
+
22
+ module DRP
23
+
24
+ module MaxDepths
25
+
26
+ # the max_depth classes are stored in class variables
27
+ # and are passed an instance of the extended user class
28
+ # so that they can ask for codons if they need them.
29
+ # they need not be copied like weights because they are
30
+ # only run once at instance initialization
31
+
32
+ class StaticMaxDepth
33
+ def initialize int
34
+ @value = int.to_i
35
+ end
36
+ def value drp_instance_unused
37
+ @value
38
+ end
39
+ end
40
+
41
+ class MappedMaxDepth
42
+ def initialize range, function = :i_linear
43
+ @range, @function = range, function
44
+ end
45
+ def value drp_instance
46
+ Utils::map(
47
+ @range,
48
+ drp_instance.next_meta_codon,
49
+ @function
50
+ )
51
+ end
52
+ end
53
+
54
+ class ProcMaxDepth
55
+ def initialize proc
56
+ @proc, @arity = proc, proc.arity
57
+ end
58
+ def value drp_instance
59
+ if @arity <= 0
60
+ @proc.call.to_i
61
+ elsif @arity == 1
62
+ @proc.call(drp_instance.next_meta_codon).to_i
63
+ else
64
+ @proc.call(*Array.new(@arity) { drp_instance.next_meta_codon }).to_i
65
+ end
66
+ end
67
+ end
68
+
69
+ end # module MaxDepths
70
+
71
+ module Weights
72
+
73
+ # user args can be array or proc
74
+ WeightArgs = Struct.new :user_args, :rule_method, :drp_instance
75
+
76
+ class AbstractWeight
77
+ def self.factory args_or_proc
78
+ proc do |rule_method, drp_instance|
79
+ self.new WeightArgs.new(args_or_proc, rule_method, drp_instance)
80
+ end
81
+ end
82
+ end
83
+
84
+ =begin
85
+ weight 10.0 static weight
86
+ weight 0..1 static mapped
87
+ weight 0..1, :function static mapped w/ function
88
+ weight {} static proc gets codons
89
+ =end
90
+
91
+ class StaticWeight < AbstractWeight
92
+ attr_reader :value
93
+ def initialize args
94
+ user_args = args.user_args
95
+ sz = user_args.size
96
+ case sz
97
+ when 1
98
+ arg = user_args[0]
99
+ case arg
100
+ when Numeric
101
+ @value = arg.to_f
102
+ when Range
103
+ @value = Utils::map(
104
+ arg,
105
+ args.drp_instance.next_meta_codon
106
+ )
107
+ else
108
+ raise ArgumentError, 'when 1 arg given to weight, must be Numeric, or Range', caller
109
+ end
110
+ when 2
111
+ rng = args[0]
112
+ func = args[1].to_sym
113
+ if (rng.kind_of? Range) && (func.kind_of? Symbol)
114
+ @value = Utils::map(
115
+ rng,
116
+ args.drp_instance.next_meta_codon,
117
+ func
118
+ )
119
+ else
120
+ raise ArgumentError, 'weight args of wrong types'
121
+ end
122
+ else
123
+ raise ArgumentError, "weight takes 1 or 2 args, #{sz} given"
124
+ end # case user_args.size
125
+ end # def initialize
126
+ end
127
+
128
+ class ProcStaticWeight < StaticWeight
129
+ def initialize args
130
+ proc = args.user_args
131
+ ar = proc.arity
132
+ inst = args.drp_instance
133
+ if ar <= 0
134
+ @value = proc.call
135
+ elsif ar == 1
136
+ @value = proc.call inst.next_meta_codon
137
+ else
138
+ @value = proc.call *Array.new(ar) { inst.next_meta_codon }
139
+ end
140
+ end
141
+ end
142
+
143
+ =begin
144
+ weight_dyn 0..1 codon maps to range for every rule method choice
145
+ weight_dyn 0..1, :function same but using function
146
+ weight_dyn 0..1, 0..1 initial min and max determined by metacodons
147
+ and further runtime mapping also
148
+ weight_dyn 0..1, 0..1, :function same but function used for runtime mapping
149
+ weight_dyn { |codon| } same but using use block, gets meta_codons
150
+ =end
151
+
152
+ =begin DYNAMIC WEIGHTS PROBABLY NOT THAT USEFUL
153
+
154
+ class DynamicWeight < AbstractWeight
155
+ def initialize args
156
+ @drp_instance = args.drp_instance
157
+ arg1, arg2, arg3 = args.user_args
158
+ if arg1.kind_of? Range
159
+ @range = arg1
160
+ if arg2.kind_of? Range
161
+ if (arg3.kind_of? Symbol) or (arg3.kind_of? String)
162
+ @function = arg3
163
+ end
164
+ min = Utils::map(@range, @drp_instance.next_meta_codon)
165
+ max = Utils::map(arg2, @drp_instance.next_meta_codon)
166
+ @range = min..max
167
+ elsif (arg2.kind_of? Symbol) or (arg2.kind_of? String)
168
+ @function = arg2
169
+ end
170
+ else
171
+ raise ArgumentError, 'weight_dyn args of wrong type'
172
+ end
173
+ end
174
+ def value
175
+ val = Utils::map(
176
+ @range,
177
+ @drp_instance.next_meta_codon,
178
+ @function
179
+ )
180
+ puts val
181
+ val
182
+ end
183
+ end
184
+
185
+ class ProcDynamicWeight < AbstractWeight
186
+ def initialize args
187
+ @proc = args.user_args
188
+ @arity = @proc.arity
189
+ @drp_instance = args.drp_instance
190
+ end
191
+ def value
192
+ case @arity
193
+ # these are here, and also ordered, for efficiencies sake
194
+ when 1
195
+ @proc.call @drp_instance.next_meta_codon
196
+ when 2
197
+ @proc.call @drp_instance.next_meta_codon, @drp_instance.next_meta_codon
198
+ when 0
199
+ raise ArgumentError, "block given to dynamic weight must have 1 or more arguments"
200
+ else
201
+ @proc.call *Array.new(@arity) { @drp_instance.next_meta_codon }
202
+ end
203
+ end
204
+ end
205
+
206
+ =end
207
+
208
+ =begin
209
+ weight_fcd 0..1 dynamic from current depth (uses max_depth)
210
+ weight_fcd 0..1, :function dynamic fcd w/ function
211
+ weight_fcd 0..1, 0..1 dynamic like previous but start
212
+ and end of range mapped from codons
213
+ weight_fcd 0..1, 0..1, :function like previous with function
214
+ the function applies to the dynamic mapping
215
+ of the current depth, and not the static
216
+ mapping via codons of start and end
217
+ which is always just linear
218
+ weight_fcd { |max_depth| dynamic, expects a block which takes the
219
+ ... max_depth and returns a proc which
220
+ proc {|depth| ... } which takes the current depth
221
+ }
222
+ =end
223
+
224
+ class WeightFromCurrentDepth < AbstractWeight
225
+ def initialize args
226
+ @drp_instance = args.drp_instance
227
+ @rule_method = args.rule_method
228
+ @max_depth = @rule_method.max_depth - 1
229
+ arg1, arg2, arg3 = args.user_args
230
+ if arg1.kind_of? Range
231
+ @range = arg1
232
+ if arg2.kind_of? Range
233
+ if (arg3.kind_of? Symbol) or (arg3.kind_of? String)
234
+ @function = arg3
235
+ end
236
+ min = Utils::map(@range, @drp_instance.next_meta_codon)
237
+ max = Utils::map(arg2, @drp_instance.next_meta_codon)
238
+ @range = min..max
239
+ elsif (arg2.kind_of? Symbol) or (arg2.kind_of? String)
240
+ @function = arg2
241
+ end
242
+ else
243
+ raise ArgumentError, 'bad argument to weight_fcd'
244
+ end
245
+ end
246
+ def value
247
+ val = @rule_method.depth.to_f / @max_depth
248
+ Utils::map(@range, val, @function)
249
+ end
250
+ end
251
+
252
+ class ProcWeightFromCurrentDepth < AbstractWeight
253
+ def initialize args
254
+ @rule_method = args.rule_method
255
+ @proc = args.user_args.call @rule_method.max_depth
256
+ end
257
+ def value
258
+ @proc.call @rule_method.depth
259
+ end
260
+ end
261
+
262
+ end # module Weights
263
+
264
+ end # module DRP
@@ -0,0 +1,219 @@
1
+
2
+ =begin
3
+
4
+ DRP, Genetic Programming + Grammatical Evolution = Directed Ruby Programming
5
+ Copyright (C) 2006, Christophe McKeon
6
+
7
+ This program is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU General Public License
9
+ as published by the Free Software Foundation; either version 2
10
+ of the License, or (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program; if not, write to the Free Softwar Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
+
20
+ =end
21
+
22
+ class TestInstanceMethodsHelper
23
+
24
+ extend DRP::RuleEngine
25
+
26
+ MAX_DEPTH = 10
27
+ MAX_DEPTH_2 = 3
28
+ DEFAULT_NUM_CODONS = 40
29
+
30
+ attr_reader :minimum_depth, :maximum_depth, :depths
31
+
32
+ def initialize codons = nil
33
+ @minimum_depth = 2000000000
34
+ @maximum_depth = 0
35
+ @depths = []
36
+ self.codons= codons
37
+ # init_drp
38
+ end
39
+
40
+ def next_codon
41
+ @codon_index = 0 if @codon_index == @num_codons
42
+ res = @codons[@codon_index]
43
+ @codon_index += 1
44
+ res
45
+ end
46
+
47
+ def codons= codons
48
+ @codons = codons || Array.new(DEFAULT_NUM_CODONS) { rand }
49
+ @codon_index = 0
50
+ @num_codons = @codons.size
51
+ end
52
+
53
+ begin_rules
54
+
55
+ ### depth tests ###
56
+
57
+ # because there is only ever one LHS
58
+ # in the follwing rules, each one is always
59
+ # picked and hence is deterministic and
60
+ # recursed to the maximum depth.
61
+
62
+ max_depth MAX_DEPTH
63
+
64
+ def test_depth_pre
65
+ register_depth
66
+ test_depth_pre
67
+ end
68
+
69
+ def test_depth_post
70
+ test_depth_post
71
+ register_depth
72
+ end
73
+
74
+ def test_depth_2_rules
75
+ @depths << depth
76
+ other_rule
77
+ test_depth_2_rules
78
+ end
79
+
80
+ max_depth MAX_DEPTH_2
81
+
82
+ def other_rule
83
+ @depths << depth
84
+ other_rule
85
+ end
86
+
87
+ end_rules
88
+
89
+ def register_depth
90
+ the_depth = depth
91
+ @depths << the_depth
92
+ # print @depths, "\n"
93
+ @minimum_depth = the_depth if the_depth < @minimum_depth
94
+ @maximum_depth = the_depth if the_depth > @maximum_depth
95
+ end
96
+
97
+ end
98
+
99
+ class TestInstanceMethods < Test::Unit::TestCase
100
+
101
+ MD = TestInstanceMethodsHelper::MAX_DEPTH
102
+ MD2 = TestInstanceMethodsHelper::MAX_DEPTH_2
103
+
104
+ def setup
105
+ @drp_obj = TestInstanceMethodsHelper.new
106
+ end
107
+
108
+ def test_depth_pre
109
+ @drp_obj.test_depth_pre
110
+ assert_equal 1, @drp_obj.minimum_depth
111
+ assert_equal MD, @drp_obj.maximum_depth
112
+ assert_equal (1..MD).to_a, @drp_obj.depths
113
+ # assert false, "NOTE: just to have a false assertion for gemspec"
114
+ end
115
+
116
+ def test_depth_post
117
+ @drp_obj.test_depth_post
118
+ assert_equal 1, @drp_obj.minimum_depth
119
+ assert_equal MD, @drp_obj.maximum_depth
120
+ assert_equal (1..MD).to_a.reverse, @drp_obj.depths
121
+ end
122
+
123
+ def test_depth_2_rules
124
+ @drp_obj.test_depth_2_rules
125
+ depths_should_be = []
126
+ MD.times do |i|
127
+ depths_should_be << (i + 1)
128
+ MD2.times do |j|
129
+ depths_should_be << (j + 1)
130
+ end
131
+ end
132
+ assert_equal depths_should_be, @drp_obj.depths
133
+ end
134
+
135
+ def test_map_range
136
+
137
+ # NOTE the following effectively tests Utils::RangeFunctions as well
138
+
139
+ assert_kind_of Float, @drp_obj.map(0..1)
140
+ assert_kind_of Float, @drp_obj.map(0.0..1.0)
141
+
142
+ single_codon 0.0
143
+
144
+ # linear function tests
145
+ r = @drp_obj.map 0..1
146
+ assert_equal r, 0.0
147
+
148
+ r = @drp_obj.map 1..0
149
+ assert_equal r, 1.0
150
+ r = @drp_obj.map -12.3..12.3
151
+ assert_equal r, -12.3
152
+ r = @drp_obj.map 12.3..-12.3
153
+ assert_equal r, 12.3
154
+
155
+ single_codon 0.5
156
+
157
+ # linear function tests
158
+ r = @drp_obj.map 0..1
159
+ assert_equal r, 0.5
160
+ r = @drp_obj.map 1..0
161
+ assert_equal r, 0.5
162
+ r = @drp_obj.map -12.3..12.3
163
+ assert_equal r, 0
164
+ r = @drp_obj.map 12.3..-12.3
165
+ assert_equal r, 0
166
+
167
+ single_codon 1.0
168
+
169
+ # linear function tests
170
+ r = @drp_obj.map 0..1
171
+ assert_equal r, 1.0
172
+ r = @drp_obj.map 1..0
173
+ assert_equal r, 0.0
174
+ r = @drp_obj.map -12.3..12.3
175
+ assert_equal r, 12.3
176
+ r = @drp_obj.map 12.3..-12.3
177
+ assert_equal r, -12.3
178
+
179
+ end
180
+
181
+ def test_map_block
182
+
183
+ num_codons = 10
184
+ codons = Array.new(num_codons) { rand }
185
+ set_codons codons
186
+
187
+ # assert_nil(codons.detect { |c| c >= 1.0 || c < 0.0 })
188
+ identity = proc { |x| x }
189
+ no_params = proc {}
190
+ local = codons.collect &identity
191
+ mapped = []
192
+
193
+ num_codons.times do
194
+ mapped << @drp_obj.map(&identity)
195
+ end
196
+
197
+ assert_equal local, mapped
198
+
199
+ # test multiple params
200
+ set_codons [1,2,3]
201
+ r = @drp_obj.map { |a,b,c,d| [a,b,c,d] }
202
+ assert_equal [1,2,3,1], r
203
+
204
+ assert_raise(ArgumentError) { @drp_obj.map &no_params }
205
+
206
+ # should not accept args and block
207
+ assert_raise(ArgumentError) { @drp_obj.map 0..1, &identity }
208
+ assert_raise(ArgumentError) { @drp_obj.map 0..1, :linear, &identity }
209
+
210
+ end
211
+
212
+ def single_codon codon
213
+ @drp_obj.codons = [codon]
214
+ end
215
+ def set_codons codons
216
+ @drp_obj.codons = codons
217
+ end
218
+
219
+ end