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,154 @@
|
|
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 InstanceMethods
|
25
|
+
|
26
|
+
# this is called when all rule methods are exhausted
|
27
|
+
# during the selection process. by default returns nil.
|
28
|
+
# you can override this in your extended class,
|
29
|
+
# but as a regular method
|
30
|
+
# not a rule method to have non-nil value returned, but
|
31
|
+
# be sure to accept an array of *args or have the arity
|
32
|
+
# correct to handle all your rule methods.
|
33
|
+
def default_rule_method *args; end
|
34
|
+
|
35
|
+
=begin
|
36
|
+
# EXTRANEOUS, CAN JUST BE DONE IN :initialize METHOD
|
37
|
+
# this is called automatically for you after
|
38
|
+
# your objects are initialized but before any codons
|
39
|
+
# are used to set weights depths etc..
|
40
|
+
# it does nothing by default
|
41
|
+
def init_codons; end
|
42
|
+
=end
|
43
|
+
|
44
|
+
# you should reimplement this method in your
|
45
|
+
# extended class, that is unless you want the
|
46
|
+
# default behaviour of an endless random stream.
|
47
|
+
# this is included mostly for quick testing purposes
|
48
|
+
def next_codon
|
49
|
+
rand
|
50
|
+
end
|
51
|
+
|
52
|
+
# this is what weights and max_depths use to get codons.
|
53
|
+
# it defaults to just using next_codon. override it in
|
54
|
+
# your extended class to have them use a separate codon stream
|
55
|
+
def next_meta_codon
|
56
|
+
next_codon
|
57
|
+
end
|
58
|
+
|
59
|
+
# how deep is the current rule method's recursion
|
60
|
+
def depth
|
61
|
+
@__drp__depth__stack.last
|
62
|
+
end
|
63
|
+
|
64
|
+
# what is the maximum depth attainable by the current rule method.
|
65
|
+
# do not confuse this with the class method setter
|
66
|
+
def max_depth
|
67
|
+
@__drp__rule__method__stack.last.max_depth
|
68
|
+
end
|
69
|
+
|
70
|
+
# don't know if these two are really worth implementing
|
71
|
+
# how many time has the current rule method executed
|
72
|
+
# including this execution
|
73
|
+
#def count
|
74
|
+
# @__drp__count__stack.last
|
75
|
+
#end
|
76
|
+
# how many times has the current rule (all rule methods)
|
77
|
+
# executed including this execution
|
78
|
+
# def rule_count
|
79
|
+
# end
|
80
|
+
|
81
|
+
# uses next_codon to output to somewhere within the range
|
82
|
+
# specified using specified function, unless a block is given
|
83
|
+
# in which case it counts the formal parameters to the block,
|
84
|
+
# and yields appropriate number of codons using next_codon
|
85
|
+
# you may not pass both a block and a range, only one or the other
|
86
|
+
def map rng = nil, function = :linear, &b # :yields: next_codon ...
|
87
|
+
if block_given?
|
88
|
+
if rng
|
89
|
+
raise ArgumentError, "both block and #{rng} passed to map", caller
|
90
|
+
end
|
91
|
+
arity = b.arity
|
92
|
+
case arity
|
93
|
+
# these are here, and also ordered, for efficiencies sake
|
94
|
+
when 1
|
95
|
+
yield next_codon
|
96
|
+
when 2
|
97
|
+
yield next_codon, next_codon
|
98
|
+
when 0, -1
|
99
|
+
raise ArgumentError, 'block given to map must have 1 or more arguments', caller
|
100
|
+
else
|
101
|
+
yield *Array.new(arity) { next_codon }
|
102
|
+
end
|
103
|
+
else
|
104
|
+
Utils::map rng, next_codon, function
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def __drp__choose__method useable_methods
|
111
|
+
|
112
|
+
weights = useable_methods.collect do |meth|
|
113
|
+
meth.weight
|
114
|
+
end
|
115
|
+
scale_by = weights.inject(0) do |weight, prev|
|
116
|
+
prev + weight
|
117
|
+
end
|
118
|
+
|
119
|
+
weights = if scale_by == 0
|
120
|
+
sz = weights.size
|
121
|
+
weight = 1.0/sz
|
122
|
+
prev_weight = 0
|
123
|
+
Array.new(sz) do
|
124
|
+
prev_weight = weight + prev_weight
|
125
|
+
end
|
126
|
+
else
|
127
|
+
prev_weight = 0
|
128
|
+
weights.collect do |weight|
|
129
|
+
prev_weight = weight / scale_by + prev_weight
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
index, codon = -1, next_codon
|
134
|
+
weights.detect do |weight|
|
135
|
+
index += 1;
|
136
|
+
codon < weight
|
137
|
+
end
|
138
|
+
|
139
|
+
useable_methods[index]
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
def __drp__call__method meth, args
|
144
|
+
@__drp__depth__stack.push(meth.depth + 1)
|
145
|
+
@__drp__rule__method__stack.push meth
|
146
|
+
res = meth.call *args
|
147
|
+
@__drp__rule__method__stack.pop
|
148
|
+
@__drp__depth__stack.pop
|
149
|
+
res
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end # module DRP
|
data/lib/pso.rb
ADDED
@@ -0,0 +1,178 @@
|
|
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
|
+
module SearchAlgorithms
|
24
|
+
module PSO
|
25
|
+
|
26
|
+
VERY_LARGE_NUMBER = 2**29
|
27
|
+
|
28
|
+
class AbstractParticleSwarmOptimizer
|
29
|
+
|
30
|
+
attr_reader :global_best_error, :global_best_vector
|
31
|
+
|
32
|
+
def initialize swarm_size, vector_size
|
33
|
+
@swarm_size, @vector_size = swarm_size, vector_size
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# must be called by subclass initialize methods
|
39
|
+
def init_particles particle_class
|
40
|
+
@particles = Array.new(@swarm_size) { particle_class.new(self,@vector_size) }
|
41
|
+
set_as_global_best @particles[rand(@swarm_size)]
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_as_global_best particle
|
45
|
+
@global_best_vector = particle.vector.dup
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class InteractiveParticle
|
51
|
+
|
52
|
+
attr_accessor :vector
|
53
|
+
|
54
|
+
def initialize pso, vector_size
|
55
|
+
@pso, @vector_size = pso, vector_size
|
56
|
+
init_vector
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_as_best
|
60
|
+
@best_vector = @vector.dup
|
61
|
+
end
|
62
|
+
def set_as_global_best
|
63
|
+
@pso.set_as_global_best self
|
64
|
+
end
|
65
|
+
|
66
|
+
def roam
|
67
|
+
gbest = @pso.global_best_vector
|
68
|
+
@vector_size.times do |i|
|
69
|
+
c = @vector[i]
|
70
|
+
pbest = @best_vector[i]
|
71
|
+
@vector[i] = c + 2 * rand * pbest - c + 2 * rand * gbest[i] - c
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def init_vector
|
76
|
+
@vector = Array.new(@vector_size) { rand }
|
77
|
+
set_as_best
|
78
|
+
end
|
79
|
+
|
80
|
+
=begin
|
81
|
+
def save name
|
82
|
+
|
83
|
+
end
|
84
|
+
def load name
|
85
|
+
if @thawed
|
86
|
+
# ...
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def freeze; @thawed = false end
|
91
|
+
def thaw; @thawed = true end
|
92
|
+
def frozen? !@thawed end
|
93
|
+
=end
|
94
|
+
end
|
95
|
+
|
96
|
+
class InteractiveParticleSwarmOptimizer < AbstractParticleSwarmOptimizer
|
97
|
+
|
98
|
+
attr_reader :particles
|
99
|
+
|
100
|
+
def initialize swarm_size, vector_size, rebirth = 0.0
|
101
|
+
super
|
102
|
+
init_particles InteractiveParticle
|
103
|
+
end
|
104
|
+
def each
|
105
|
+
@particles.each do |p|
|
106
|
+
yield p
|
107
|
+
end
|
108
|
+
end
|
109
|
+
def roam_all
|
110
|
+
each { |p| p.roam }
|
111
|
+
end
|
112
|
+
def reinit_all
|
113
|
+
each { |p| p.init_vector }
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
class Particle < InteractiveParticle
|
119
|
+
def initialize pso, vector_size
|
120
|
+
@best_error = VERY_LARGE_NUMBER
|
121
|
+
super
|
122
|
+
end
|
123
|
+
def optimize error
|
124
|
+
if error < @best_error
|
125
|
+
@best_error = error
|
126
|
+
set_as_best
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class ParticleSwarmOptimizer < AbstractParticleSwarmOptimizer
|
132
|
+
|
133
|
+
def initialize swarm_size, vector_size, rebirth = 0.0
|
134
|
+
@global_best_error = VERY_LARGE_NUMBER
|
135
|
+
@num_reborn = (swarm_size * rebirth).to_i
|
136
|
+
@rebirth_index = 0
|
137
|
+
super swarm_size, vector_size
|
138
|
+
init_particles Particle
|
139
|
+
end
|
140
|
+
|
141
|
+
def each
|
142
|
+
rebirth
|
143
|
+
best_this_time = VERY_LARGE_NUMBER
|
144
|
+
@particles.each do |p|
|
145
|
+
v = p.vector
|
146
|
+
error = yield v
|
147
|
+
if error < @global_best_error
|
148
|
+
@global_best_vector = v.dup
|
149
|
+
@global_best_error = error
|
150
|
+
end
|
151
|
+
if error < best_this_time
|
152
|
+
best_this_time = error
|
153
|
+
end
|
154
|
+
p.optimize error
|
155
|
+
p.roam
|
156
|
+
end
|
157
|
+
#puts best_this_time
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
# my non-standard addition to pso algorithm
|
163
|
+
# the idea being brutal removal from local optima.
|
164
|
+
# cycles through particles to give the reborn
|
165
|
+
# a chance to roam a bit before being reborn yet again.
|
166
|
+
def rebirth
|
167
|
+
@num_reborn.times do
|
168
|
+
@rebirth_index = 0 if @rebirth_index == @swarm_size
|
169
|
+
@particles[@rebirth_index].init_vector
|
170
|
+
@rebirth_index += 1
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end # module PSO
|
177
|
+
end # module SearchAlgoritms
|
178
|
+
end # module DRP
|
data/lib/rule_engine.rb
ADDED
@@ -0,0 +1,324 @@
|
|
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
|
+
class RuleMethod
|
25
|
+
|
26
|
+
attr_reader :depth, :max_depth
|
27
|
+
|
28
|
+
def initialize drp_instance, method_name, weight_factory, max_depth
|
29
|
+
@method = drp_instance.method method_name
|
30
|
+
@max_depth = max_depth.value drp_instance
|
31
|
+
@weight = weight_factory.call self, drp_instance
|
32
|
+
@depth = 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def expressed?
|
36
|
+
@depth < @max_depth
|
37
|
+
end
|
38
|
+
|
39
|
+
def call *args
|
40
|
+
@depth += 1
|
41
|
+
result = @method.call *args
|
42
|
+
@depth -= 1
|
43
|
+
result
|
44
|
+
end
|
45
|
+
|
46
|
+
def weight
|
47
|
+
@weight.value
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
module RuleEngine
|
53
|
+
|
54
|
+
def new *a, &b
|
55
|
+
super.__drp__init
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def self.extend_object klass
|
61
|
+
DRPNameClashError.test(klass) if DEFAULT[:test_for_extend_name_clashes]
|
62
|
+
klass.class_eval do
|
63
|
+
include InstanceMethods
|
64
|
+
end
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_added name
|
69
|
+
# explicit boolean test because can also be :finished
|
70
|
+
if @__drp__defining_rules == true
|
71
|
+
|
72
|
+
rule = @__drp__rules[name] ||= []
|
73
|
+
|
74
|
+
# to stop recursion of method_added due to alias which calls it
|
75
|
+
@__drp__defining_rules = false
|
76
|
+
class_eval "private :#{name}; alias __drp__#{name}__#{rule.size} #{name}"
|
77
|
+
@__drp__defining_rules = true
|
78
|
+
|
79
|
+
# note this comes after class_eval cuz of ref to rule.size there
|
80
|
+
rule << [@__drp__weights.last, @__drp__max__depths.last]
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# TODO find way of making rdoc document these even if they are private
|
86
|
+
public
|
87
|
+
|
88
|
+
def begin_rules
|
89
|
+
# if it is true or :finished, see end_rules & method_added
|
90
|
+
if @__drp__defining_rules
|
91
|
+
raise DRPError, 'begin rules may only be called once'
|
92
|
+
else
|
93
|
+
@__drp__rules = {}
|
94
|
+
@__drp__defining_rules = true
|
95
|
+
@__drp__weights = []
|
96
|
+
@__drp__max__depths = []
|
97
|
+
# NB max_depth should come first here in case user changes
|
98
|
+
# the default to some weight which needs to know the max_depth
|
99
|
+
max_depth DEFAULT[:max_depth]
|
100
|
+
weight DEFAULT[:weight]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# NB the two methods defined via define_method in end_rules
|
105
|
+
# will be instance methods in instances of classes which
|
106
|
+
# are extended by this module. they are here because they
|
107
|
+
# are closures referencing the 'name' and 'all_methods'
|
108
|
+
# variables respectively.
|
109
|
+
# other non-closure methods are in module InstanceMethods
|
110
|
+
|
111
|
+
def end_rules
|
112
|
+
|
113
|
+
@__drp__defining_rules = :finished
|
114
|
+
|
115
|
+
all_methods = {}
|
116
|
+
|
117
|
+
@__drp__rules.each do |name, weights_and_max_depths|
|
118
|
+
|
119
|
+
methods = []
|
120
|
+
|
121
|
+
weights_and_max_depths.each_with_index do |w_md, i|
|
122
|
+
methods.push ["__drp__#{name}__#{i}"] + w_md
|
123
|
+
end
|
124
|
+
|
125
|
+
all_methods[name] = methods
|
126
|
+
|
127
|
+
define_method name do |*args|
|
128
|
+
|
129
|
+
useable_methods = @__drp__rule__methods[name].select do |meth|
|
130
|
+
meth.expressed?
|
131
|
+
end
|
132
|
+
|
133
|
+
case useable_methods.size
|
134
|
+
|
135
|
+
when 0
|
136
|
+
default_rule_method *args
|
137
|
+
|
138
|
+
when 1
|
139
|
+
__drp__call__method(useable_methods.first, args)
|
140
|
+
|
141
|
+
else
|
142
|
+
__drp__call__method(__drp__choose__method(useable_methods), args)
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end # define_method name do
|
147
|
+
|
148
|
+
|
149
|
+
end # @__drp__rules.each do
|
150
|
+
|
151
|
+
define_method :__drp__init do
|
152
|
+
|
153
|
+
@__drp__rule__methods = {}
|
154
|
+
@__drp__depth__stack = []
|
155
|
+
@__drp__rule__method__stack = []
|
156
|
+
|
157
|
+
all_methods.each do |name, arg_array|
|
158
|
+
@__drp__rule__methods[name] = arg_array.collect do |args|
|
159
|
+
RuleMethod.new self, *args
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
self
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end # end_rules
|
168
|
+
|
169
|
+
=begin rdoc
|
170
|
+
|
171
|
+
sets the maximum obtainable depth of the rule methods which follow it
|
172
|
+
in the listing. max_depths are set for each instance of the class you
|
173
|
+
extended with DRP::RuleEngine upon initialization (or when you call init_drp),
|
174
|
+
once and only once, and remains set to that static value. max depths are always
|
175
|
+
integer values.
|
176
|
+
|
177
|
+
it may be used in any of the following four ways:
|
178
|
+
|
179
|
+
*scalar*, all following rule_methods are set to given value
|
180
|
+
|
181
|
+
max_depth 1
|
182
|
+
|
183
|
+
*range*, each following rule_method is initialized to some integer
|
184
|
+
from range.start to range.end inclusive using a linear mapping
|
185
|
+
of a codon gotten via the method next_meta_codon.
|
186
|
+
|
187
|
+
max_depth 1..2
|
188
|
+
|
189
|
+
same as the previous but uses the function given, at present
|
190
|
+
the only function implemented is i_linear (integer linear),
|
191
|
+
which is the default action when no function is given, so at
|
192
|
+
present this is useless.
|
193
|
+
|
194
|
+
max_depth 1..2, :function
|
195
|
+
|
196
|
+
*block*, each following rule_method is initialized to some integer
|
197
|
+
given by your block. the formal parameters to your supplied
|
198
|
+
block are counted, and the appropriate number of codons harvested using
|
199
|
+
InstanceMethods#next_meta_codon are passed to the block.
|
200
|
+
|
201
|
+
max_depth { |next_meta_codon, ...| ... }
|
202
|
+
|
203
|
+
see example_2.rb
|
204
|
+
|
205
|
+
=end
|
206
|
+
|
207
|
+
def max_depth *args, &block
|
208
|
+
|
209
|
+
sz = args.size
|
210
|
+
are_args = sz > 0
|
211
|
+
md = nil
|
212
|
+
|
213
|
+
if block_given?
|
214
|
+
if are_args
|
215
|
+
raise ArgumentError, 'max_depth called with both arguments and a block', caller
|
216
|
+
else
|
217
|
+
md = MaxDepths::ProcMaxDepth.new(block)
|
218
|
+
end
|
219
|
+
else
|
220
|
+
case sz
|
221
|
+
when 1
|
222
|
+
arg = args[0]
|
223
|
+
case arg
|
224
|
+
when Numeric
|
225
|
+
md = MaxDepths::StaticMaxDepth.new arg.to_i
|
226
|
+
when Range
|
227
|
+
md = MaxDepths::MappedMaxDepth.new arg
|
228
|
+
else
|
229
|
+
raise ArgumentError, 'bad argument to max_depth', caller
|
230
|
+
end
|
231
|
+
when 2
|
232
|
+
arg1, arg2 = args
|
233
|
+
if (arg1.kind_of? Range) && (arg2.kind_of? Symbol)
|
234
|
+
md = MaxDepths::MappedMaxDepth.new arg1, arg2
|
235
|
+
else
|
236
|
+
raise ArgumentError, 'bad argument to max_depth', caller
|
237
|
+
end
|
238
|
+
else
|
239
|
+
raise ArgumentError, "too many (#{sz}) args passed to max_depth", caller
|
240
|
+
end # case sz
|
241
|
+
end # if block_given
|
242
|
+
|
243
|
+
@__drp__max__depths << md
|
244
|
+
|
245
|
+
end # def max_depth
|
246
|
+
|
247
|
+
=begin rdoc
|
248
|
+
|
249
|
+
sets the weight of the rule methods which follow it
|
250
|
+
in the listing, and may be used in any of the following four ways:
|
251
|
+
|
252
|
+
*scalar*, all following rule_methods are set to given value
|
253
|
+
|
254
|
+
max_depth 1
|
255
|
+
|
256
|
+
*range*, each following rule_method is initialized to some integer
|
257
|
+
from range.start to range.end inclusive using a linear mapping
|
258
|
+
of a codon gotten via the method next_meta_codon when your
|
259
|
+
extended object is initialized via drp_init.
|
260
|
+
|
261
|
+
max_depth 1..2
|
262
|
+
|
263
|
+
same as the previous but uses the function given, at present
|
264
|
+
the only function implemented is i_linear (integer linear),
|
265
|
+
which is the default action when no function is given, so at
|
266
|
+
present this is useless.
|
267
|
+
|
268
|
+
max_depth 1..2, :function
|
269
|
+
|
270
|
+
*block*, each following rule_method is initialized to some integer
|
271
|
+
given by your block upon a call to drp_init, i.e. when you initialize
|
272
|
+
your extended object instance. the formal parameters to your supplied
|
273
|
+
block are counted, and the appropriate number of codons harvested using
|
274
|
+
InstanceMethods#next_meta_codon are passed to the block.
|
275
|
+
|
276
|
+
max_depth { |next_meta_codon, ...| ... }
|
277
|
+
|
278
|
+
=end
|
279
|
+
|
280
|
+
|
281
|
+
def weight *args, &block
|
282
|
+
bg, are_args = block_given?, args.size > 0
|
283
|
+
if bg && are_args
|
284
|
+
raise ArgumentError, 'weight called with both arguments and a block', caller
|
285
|
+
elsif bg
|
286
|
+
@__drp__weights << Weights::ProcStaticWeight.factory(block)
|
287
|
+
elsif are_args
|
288
|
+
@__drp__weights << Weights::StaticWeight.factory(args)
|
289
|
+
else
|
290
|
+
raise ArgumentError, 'weight called with neither args nor block', caller
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
=begin NOT REALLY USEFUL
|
295
|
+
def weight_dyn *args, &block
|
296
|
+
bg, are_args = block_given?, args.size > 0
|
297
|
+
if bg && are_args
|
298
|
+
__drp__error "weight_dyn called with both args and block"
|
299
|
+
elsif bg
|
300
|
+
@__drp__weights << Weights::ProcDynamicWeight.factory(block)
|
301
|
+
elsif are_args
|
302
|
+
@__drp__weights << Weights::DynamicWeight.factory(args)
|
303
|
+
else
|
304
|
+
raise ArgumentError, 'weight_dyn called with neither args nor block', caller
|
305
|
+
end
|
306
|
+
end
|
307
|
+
=end
|
308
|
+
|
309
|
+
def weight_fcd *args, &block
|
310
|
+
bg, are_args = block_given?, args.size > 0
|
311
|
+
if bg && are_args
|
312
|
+
__drp__error "weight_fcd called with both args and block"
|
313
|
+
elsif bg
|
314
|
+
@__drp__weights << Weights::ProcWeightFromCurrentDepth.factory(block)
|
315
|
+
elsif are_args
|
316
|
+
@__drp__weights << Weights::WeightFromCurrentDepth.factory(args)
|
317
|
+
else
|
318
|
+
raise ArgumentError, 'weight_fcd called with neither args nor block', caller
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
end # class RuleEngine
|
323
|
+
|
324
|
+
end # module DRP
|