drp 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +6 -0
- data/CHANGES +0 -0
- data/INTRO +309 -0
- data/LICENSE +281 -0
- data/README +77 -0
- data/Rakefile +99 -0
- data/TODO +13 -0
- data/examples/intro/README +2 -0
- data/examples/intro/canvas_example.rb +123 -0
- data/examples/intro/max_depths_example.rb +34 -0
- data/examples/intro/max_depths_example_2.rb +30 -0
- data/examples/intro/odds_and_ends.rb +96 -0
- data/examples/intro/parameterization_example.rb +32 -0
- data/examples/intro/toy_example.rb +22 -0
- data/examples/intro/weight_fcd_example.rb +44 -0
- data/examples/intro/weights_example.rb +33 -0
- data/examples/intro/weights_example_2.rb +30 -0
- data/examples/symbolic_regression.rb +127 -0
- data/lib/defaults.rb +30 -0
- data/lib/drp.rb +30 -0
- data/lib/error.rb +69 -0
- data/lib/info.rb +30 -0
- data/lib/instance_methods.rb +154 -0
- data/lib/pso.rb +178 -0
- data/lib/rule_engine.rb +324 -0
- data/lib/utils.rb +67 -0
- data/lib/weights_and_max_depths.rb +264 -0
- data/test/tc_instance_methods.rb +219 -0
- data/test/tc_max_depths.rb +98 -0
- data/test/tc_utils.rb +60 -0
- data/test/tc_weights.rb +372 -0
- data/test/ts_drp.rb +28 -0
- metadata +80 -0
@@ -0,0 +1,98 @@
|
|
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 TestMaxDepthsHelper
|
23
|
+
|
24
|
+
extend DRP::RuleEngine
|
25
|
+
|
26
|
+
attr_reader :test_simple_depth_attained
|
27
|
+
|
28
|
+
def initialize single_codon = nil
|
29
|
+
@test_simple_depth_attained = 0
|
30
|
+
@single_codon = single_codon
|
31
|
+
# init_drp
|
32
|
+
end
|
33
|
+
|
34
|
+
# note max_depths call next_meta_codon
|
35
|
+
# but their is a default next_meta_codon which
|
36
|
+
# just calls next_codon
|
37
|
+
def next_codon
|
38
|
+
@single_codon || rand
|
39
|
+
end
|
40
|
+
|
41
|
+
begin_rules
|
42
|
+
|
43
|
+
# note, some of these tests depend on the return
|
44
|
+
# value of default_rule_method below
|
45
|
+
|
46
|
+
max_depth 4
|
47
|
+
def test_simple
|
48
|
+
test_simple + 1
|
49
|
+
end
|
50
|
+
|
51
|
+
max_depth 3..9
|
52
|
+
def test_map_range
|
53
|
+
test_map_range + 1
|
54
|
+
end
|
55
|
+
|
56
|
+
max_depth { |x,y| x + y }
|
57
|
+
def test_proc
|
58
|
+
test_proc + 1
|
59
|
+
end
|
60
|
+
|
61
|
+
end_rules
|
62
|
+
|
63
|
+
def default_rule_method
|
64
|
+
0
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
class TestMaxDepths < Test::Unit::TestCase
|
70
|
+
|
71
|
+
def test_exceptions
|
72
|
+
# TODO
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_simple
|
76
|
+
@drp_obj = TestMaxDepthsHelper.new
|
77
|
+
assert_equal 4, @drp_obj.test_simple
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_map_range
|
81
|
+
7.times do |i|
|
82
|
+
codon = i/7.0
|
83
|
+
@drp_obj = TestMaxDepthsHelper.new codon
|
84
|
+
#puts "i: #{i}, cod: #{codon}, map: #{@drp_obj.test_map_range}"
|
85
|
+
assert_equal i + 3, @drp_obj.test_map_range
|
86
|
+
end
|
87
|
+
@drp_obj = TestMaxDepthsHelper.new 0.99999999999
|
88
|
+
assert_equal 9, @drp_obj.test_map_range
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_proc
|
92
|
+
@drp_obj = TestMaxDepthsHelper.new 3
|
93
|
+
assert_equal 6, @drp_obj.test_proc
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
|
data/test/tc_utils.rb
ADDED
@@ -0,0 +1,60 @@
|
|
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
|
+
# TODO test if the range is of the form n..n where n is the same number
|
23
|
+
|
24
|
+
class TestUtils < Test::Unit::TestCase
|
25
|
+
|
26
|
+
def test_i_linear_map
|
27
|
+
|
28
|
+
r = 0..4
|
29
|
+
|
30
|
+
assert_equal 0, DRP::Utils::map(r, 0, :i_linear)
|
31
|
+
assert_equal 0, DRP::Utils::map(r, 0.19999, :i_linear)
|
32
|
+
assert_equal 1, DRP::Utils::map(r, 0.2, :i_linear)
|
33
|
+
assert_equal 1, DRP::Utils::map(r, 0.39999, :i_linear)
|
34
|
+
assert_equal 2, DRP::Utils::map(r, 0.4, :i_linear)
|
35
|
+
assert_equal 2, DRP::Utils::map(r, 0.59999, :i_linear)
|
36
|
+
assert_equal 3, DRP::Utils::map(r, 0.6, :i_linear)
|
37
|
+
assert_equal 3, DRP::Utils::map(r, 0.79999, :i_linear)
|
38
|
+
assert_equal 4, DRP::Utils::map(r, 0.8, :i_linear)
|
39
|
+
assert_equal 4, DRP::Utils::map(r, 0.99999, :i_linear)
|
40
|
+
# this is 5 but codons need to be 0 <= c < 1 so it should never happen
|
41
|
+
# assert_equal 5, DRP::Utils::map(r, 1, :i_linear)
|
42
|
+
|
43
|
+
r = 4..0
|
44
|
+
|
45
|
+
assert_equal 4, DRP::Utils::map(r, 0, :i_linear)
|
46
|
+
assert_equal 4, DRP::Utils::map(r, 0.19999, :i_linear)
|
47
|
+
assert_equal 3, DRP::Utils::map(r, 0.2, :i_linear)
|
48
|
+
assert_equal 3, DRP::Utils::map(r, 0.39999, :i_linear)
|
49
|
+
assert_equal 2, DRP::Utils::map(r, 0.4, :i_linear)
|
50
|
+
assert_equal 2, DRP::Utils::map(r, 0.59999, :i_linear)
|
51
|
+
assert_equal 1, DRP::Utils::map(r, 0.6, :i_linear)
|
52
|
+
assert_equal 1, DRP::Utils::map(r, 0.79999, :i_linear)
|
53
|
+
assert_equal 0, DRP::Utils::map(r, 0.8, :i_linear)
|
54
|
+
assert_equal 0, DRP::Utils::map(r, 0.99999, :i_linear)
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
data/test/tc_weights.rb
ADDED
@@ -0,0 +1,372 @@
|
|
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
|
+
############### STATIC WEIGHTS ###############
|
23
|
+
|
24
|
+
=begin
|
25
|
+
weight 10.0 static weight
|
26
|
+
weight 0..1 static mapped
|
27
|
+
weight 0..1, :function static mapped w/ function
|
28
|
+
weight {} static proc gets codons
|
29
|
+
=end
|
30
|
+
|
31
|
+
class TestStaticWeightsHelper
|
32
|
+
|
33
|
+
extend DRP::RuleEngine
|
34
|
+
|
35
|
+
attr_writer :codon
|
36
|
+
attr_reader :_1, :_0, :_33, :_67, :_m1, :_m01_02, :_p30, :_p70
|
37
|
+
|
38
|
+
def initialize codon = nil
|
39
|
+
@codon = codon
|
40
|
+
@_1 = @_0 = @_33 = @_67 = @_m1 = @_m01_02 = @_p30 = @_p70 = 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def next_codon
|
44
|
+
@codon || rand
|
45
|
+
end
|
46
|
+
|
47
|
+
begin_rules
|
48
|
+
|
49
|
+
# test constant
|
50
|
+
|
51
|
+
weight 1
|
52
|
+
def _1_0
|
53
|
+
@_1 += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
weight 0
|
57
|
+
def _1_0
|
58
|
+
@_0 += 1
|
59
|
+
end
|
60
|
+
|
61
|
+
weight 33
|
62
|
+
def _33_67
|
63
|
+
@_33 += 1
|
64
|
+
end
|
65
|
+
|
66
|
+
weight 67
|
67
|
+
def _33_67
|
68
|
+
@_67 += 1
|
69
|
+
end
|
70
|
+
|
71
|
+
# test mapped
|
72
|
+
|
73
|
+
weight 0.1..0.2
|
74
|
+
def mapped
|
75
|
+
@_m01_02 += 1
|
76
|
+
end
|
77
|
+
|
78
|
+
weight 1
|
79
|
+
def mapped
|
80
|
+
@_m1 += 1
|
81
|
+
end
|
82
|
+
|
83
|
+
# test proc
|
84
|
+
|
85
|
+
weight { |x,y,z| ((x + y + z) * 100).to_i }
|
86
|
+
def proc
|
87
|
+
@_p30 += 1
|
88
|
+
end
|
89
|
+
|
90
|
+
weight 70
|
91
|
+
def proc
|
92
|
+
@_p70 += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
end_rules
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
class TestStaticWeights < Test::Unit::TestCase
|
100
|
+
|
101
|
+
def test_constant
|
102
|
+
ts = TestStaticWeightsHelper.new
|
103
|
+
100.times do |i|
|
104
|
+
ts.codon = i.to_f/100
|
105
|
+
ts._1_0
|
106
|
+
ts._33_67
|
107
|
+
end
|
108
|
+
assert_equal 100, ts._1
|
109
|
+
assert_equal 0, ts._0
|
110
|
+
assert_equal 33, ts._33
|
111
|
+
assert_equal 67, ts._67
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_mapped
|
115
|
+
ts = TestStaticWeightsHelper.new
|
116
|
+
100.times do |i|
|
117
|
+
ts.codon = i.to_f/100
|
118
|
+
ts.mapped
|
119
|
+
end
|
120
|
+
m = ts._m01_02
|
121
|
+
m1 = ts._m1
|
122
|
+
# puts ">>>>>", m, m1, "<<<<<"
|
123
|
+
# these figures take normalization into account
|
124
|
+
assert m >= 9 && m <= 17
|
125
|
+
assert m1 >= 83
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_mapped_w_function
|
129
|
+
# TODO no functions yet
|
130
|
+
assert true
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_proc
|
134
|
+
ts = TestStaticWeightsHelper.new(0.1)
|
135
|
+
# since the codon is set here
|
136
|
+
# to 0.1 then (x + y + z) * 100 in proc equal 30
|
137
|
+
100.times do |i|
|
138
|
+
ts.codon = i.to_f/100
|
139
|
+
ts.proc
|
140
|
+
end
|
141
|
+
assert_equal 30, ts._p30
|
142
|
+
assert_equal 70, ts._p70
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
############### FROM CURRENT DEPTH WEIGHTS ##################
|
148
|
+
|
149
|
+
|
150
|
+
=begin
|
151
|
+
weight_fcd 0..1 dynamic from current depth (uses max_depth)
|
152
|
+
weight_fcd 0..1, :function dynamic fcd w/ function
|
153
|
+
weight_fcd 0..1, 0..1 dynamic like previous but start
|
154
|
+
and end of range mapped from codons
|
155
|
+
weight_fcd 0..1, 0..1, :function like previous with function
|
156
|
+
the function applies to the dynamic mapping
|
157
|
+
of the current depth, and not the static
|
158
|
+
mapping via codons of start and end
|
159
|
+
which is always just linear
|
160
|
+
weight_fcd { |max_depth| dynamic, expects a block which takes the
|
161
|
+
... max_depth and returns a proc which
|
162
|
+
proc {|depth| ... } which takes the current depth
|
163
|
+
}
|
164
|
+
=end
|
165
|
+
|
166
|
+
class TestFCDWeightsHelper
|
167
|
+
|
168
|
+
extend DRP::RuleEngine
|
169
|
+
|
170
|
+
attr_reader :str
|
171
|
+
|
172
|
+
def initialize
|
173
|
+
reset
|
174
|
+
end
|
175
|
+
def reset
|
176
|
+
@str = ''
|
177
|
+
end
|
178
|
+
|
179
|
+
begin_rules
|
180
|
+
|
181
|
+
max_depth 3
|
182
|
+
|
183
|
+
weight_fcd 1.0..0.0
|
184
|
+
def simple
|
185
|
+
@str << 'a'
|
186
|
+
# print @str, '>>', depth, "\n"
|
187
|
+
simple
|
188
|
+
end
|
189
|
+
|
190
|
+
weight_fcd 0.0..1.0
|
191
|
+
def simple
|
192
|
+
@str << 'b'
|
193
|
+
# print @str, '>>', depth, "\n"
|
194
|
+
simple
|
195
|
+
end
|
196
|
+
|
197
|
+
end_rules
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
class TestFCDWeights < Test::Unit::TestCase
|
202
|
+
|
203
|
+
def test_simple
|
204
|
+
td = TestFCDWeightsHelper.new
|
205
|
+
100.times do
|
206
|
+
td.simple
|
207
|
+
# on first pick 'a' must be chosen w/ 1.0 vs 0.0 weight
|
208
|
+
# on second pick 'a' must be chosen with 0.5 vs 0 weight
|
209
|
+
# on third pick 'a' and 'b' both have weight 0 so
|
210
|
+
# either can be chosen
|
211
|
+
# if 'a' was chosen on third then
|
212
|
+
# all the rest will be 'b' because 'a' has exceeded max depth 3
|
213
|
+
# else
|
214
|
+
# on fourth pick 'b' must be chosen because it now has weight
|
215
|
+
# 0.5 vs 'a' which still has weight 0.0
|
216
|
+
# on fifth pick 'b' must be chosen because it now has weight 1.0
|
217
|
+
# on sixth pick 'a' is the only active rule method because 'b' has
|
218
|
+
# gone past it's max_depth, so 'a' must be picked
|
219
|
+
assert ('aaabbb' == td.str) || ('aabbba' == td.str)
|
220
|
+
td.reset
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
##############################################################
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
############### DYNAMIC WEIGHTS ##############
|
236
|
+
|
237
|
+
=begin
|
238
|
+
weight_dyn 0..1 codon maps to range for every rule method choice
|
239
|
+
weight_dyn 0..1, :function same but using function
|
240
|
+
weight_dyn 0..1, 0..1 initial min and max determined by metacodons
|
241
|
+
and further runtime mapping also
|
242
|
+
weight_dyn 0..1, 0..1, :function same but function used for runtime mapping
|
243
|
+
weight_dyn { |codon| } same but using user block, gets meta_codons
|
244
|
+
=end
|
245
|
+
|
246
|
+
=begin NOT SURE HOW USEFUL 'DYNAMIC' WEIGHTS ARE
|
247
|
+
|
248
|
+
class TestDynamicWeightsHelper
|
249
|
+
|
250
|
+
extend DRP::RuleEngine
|
251
|
+
|
252
|
+
attr_reader :test_simple_count, :num_meta_codon_requests, :num_codon_requests
|
253
|
+
|
254
|
+
def initialize codon = nil
|
255
|
+
@codon = codon
|
256
|
+
reset
|
257
|
+
end
|
258
|
+
|
259
|
+
def next_codon
|
260
|
+
@num_codon_requests += 1
|
261
|
+
@codon || rand
|
262
|
+
end
|
263
|
+
|
264
|
+
def next_meta_codon
|
265
|
+
@num_meta_codon_requests += 1
|
266
|
+
rand
|
267
|
+
end
|
268
|
+
|
269
|
+
def reset
|
270
|
+
@num_codon_requests = 0
|
271
|
+
@num_meta_codon_requests = 0
|
272
|
+
end
|
273
|
+
|
274
|
+
begin_rules
|
275
|
+
|
276
|
+
weight_dyn 0..1
|
277
|
+
def test_simple
|
278
|
+
end
|
279
|
+
def test_simple
|
280
|
+
end
|
281
|
+
|
282
|
+
weight_dyn 0..1, 0..1
|
283
|
+
def test_init_range
|
284
|
+
end
|
285
|
+
def test_init_range
|
286
|
+
end
|
287
|
+
|
288
|
+
end_rules
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
class TestDynamicWeights < Test::Unit::TestCase
|
293
|
+
|
294
|
+
# this is a very indirect test
|
295
|
+
def test_simple
|
296
|
+
td = TestDynamicWeightsHelper.new
|
297
|
+
# 4 meta_codons are used to initialize test_init_range weights
|
298
|
+
# so need to reset
|
299
|
+
td.reset
|
300
|
+
n = 10
|
301
|
+
n.times do
|
302
|
+
td.test_simple
|
303
|
+
end
|
304
|
+
# both test_simple rule methods get weights
|
305
|
+
# allocated via meta_codons for each and every choice
|
306
|
+
assert_equal n * 2, td.num_meta_codon_requests
|
307
|
+
# once the weights are set a rule must be
|
308
|
+
# picked which uses a regular codon
|
309
|
+
assert_equal n, td.num_codon_requests
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_init_range
|
313
|
+
td = TestDynamicWeightsHelper.new
|
314
|
+
# 4 meta_codons are used to initialize test_init_range weights
|
315
|
+
assert_equal 4, td.num_meta_codon_requests
|
316
|
+
n = 10
|
317
|
+
n.times do
|
318
|
+
td.test_init_range
|
319
|
+
end
|
320
|
+
# both test_init_range rule methods get
|
321
|
+
# their initial weight range set at initialization time
|
322
|
+
# which requires 2 metacodons each.
|
323
|
+
assert_equal (n * 2) + 4, td.num_meta_codon_requests
|
324
|
+
# once the weights are set a rule must be
|
325
|
+
# picked which uses a regular codon
|
326
|
+
assert_equal n, td.num_codon_requests
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
=end
|
332
|
+
|
333
|
+
|
334
|
+
=begin
|
335
|
+
|
336
|
+
ITER_TEST_DEFAULT_NUM_ITER = 1000
|
337
|
+
ITER_TEST_MAX_NUM_ITER = 100000
|
338
|
+
|
339
|
+
def iter_test(
|
340
|
+
test_helper, selector, expected = true,
|
341
|
+
num_iter = ITER_TEST_DEFAULT_NUM_ITER,
|
342
|
+
max_num_iter = ITER_TEST_MAX_NUM_ITER
|
343
|
+
)
|
344
|
+
|
345
|
+
if num_iter > max_num_iter
|
346
|
+
return false
|
347
|
+
end
|
348
|
+
|
349
|
+
test = true
|
350
|
+
num_iter.times do
|
351
|
+
test &&= test_helper.send(selector)
|
352
|
+
end
|
353
|
+
|
354
|
+
if test == expected
|
355
|
+
return true
|
356
|
+
else
|
357
|
+
return iter_test(test_helper, selector, expected, num_iter * 2, max_num_iter)
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
# non deterministic assert
|
363
|
+
def nd_assert test_helper, selector, expected = true
|
364
|
+
val = iter_test(test_helper, selector, expected)
|
365
|
+
msg = "nondeterministic test failure: '#{selector}', " +
|
366
|
+
# TODO these instructions should be in the docs
|
367
|
+
"run 'rake test' a few more times to double check"
|
368
|
+
assert val, msg
|
369
|
+
end
|
370
|
+
|
371
|
+
=end
|
372
|
+
|