drp 0.0.6

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.
@@ -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