1 | /* |
---|
2 | Copyright 2006 by Sean Luke and George Mason University |
---|
3 | Licensed under the Academic Free License version 3.0 |
---|
4 | See the file "LICENSE" for more information |
---|
5 | */ |
---|
6 | |
---|
7 | |
---|
8 | package ec.rule; |
---|
9 | import ec.*; |
---|
10 | import ec.util.*; |
---|
11 | |
---|
12 | /* |
---|
13 | * RuleSetConstraints.java |
---|
14 | * |
---|
15 | * Created: Tue Feb 20 13:26:00 2001 |
---|
16 | * By: Liviu Panait and Sean Luke |
---|
17 | */ |
---|
18 | |
---|
19 | /** |
---|
20 | * RuleSetConstraints is an basic class for constraints applicable to rulesets. |
---|
21 | * There are two categories of parameters associated with this class. First, there are parameters |
---|
22 | * which guide the initial number of rules to be created when a ruleset is initialized for |
---|
23 | * the first time, or totally reset. Second, there are parameters which indicate how rulesets |
---|
24 | * are to be mutated under the "default" rule mutation operator. |
---|
25 | * |
---|
26 | * <p>First the initialization parameters. You need to specify a distribution from which |
---|
27 | * the system will pick random integer values X. When a ruleset is to be initialized, a |
---|
28 | * random value X is picked from this distribution, and the ruleset will be created with X initial rules. |
---|
29 | * You can specify the distribution in one of two ways. First, you can specify a minimum and maximum |
---|
30 | * number of rules; the system will then pick an X uniformly from between the min and the max. |
---|
31 | * Second, you can specify a full distribution of size probabilities for more control. For example, |
---|
32 | * to specify that the system should make individuals with 0 rules 0.1 of the time, 1 rule 0.2 of the time, |
---|
33 | * and 2 rules 0.7 of the time, you set <i>reset-num-sizes</i> to 3 (for rule sizes up to but not including 3), |
---|
34 | * and then set reset-size.0 to 0.1, reset-size.1 to 0.2, and reset-size.2 to 0.7. |
---|
35 | * |
---|
36 | * <p>Next the mutation parameters. The default mutation procedure works as follows. First, every rule |
---|
37 | * in the ruleset is mutated. It is up to the rule to determine by how much or whether it will be mutated |
---|
38 | * (perhaps by flipping a coin) when its mutate function is called. Second, the system repeatedly flips |
---|
39 | * a coin with "p-del" probability of being true, until it comes up false. The number of times it came up |
---|
40 | * true is the number of rules to remove from the ruleset; rules to be removed are chosen at random. |
---|
41 | * Third, the system repeatedly flips |
---|
42 | * a coin with "p-add" probability of being true, until it comes up false. The number of times it came up |
---|
43 | * true is the number of new randomly-generated rules to add to the ruleset; rules are added to the end of the array. |
---|
44 | * Fourth, with "p-rand-order" probability, the order of rules in the ruleset array is randomized; this last |
---|
45 | * item might or might not matter to you depending on whether or not your rule interpreter differs depending on rule order. |
---|
46 | * |
---|
47 | * @author Liviu Panait and Sean Luke |
---|
48 | * @version 1.0 |
---|
49 | |
---|
50 | <p><b>Parameters</b><br> |
---|
51 | <table> |
---|
52 | <tr><td valign=top><i>base</i>.<tt>size</tt><br> |
---|
53 | <font size=-1>int >= 1</font></td> |
---|
54 | <td valign=top>(number of rule set constraints)</td></tr> |
---|
55 | |
---|
56 | <tr><td valign=top><i>base.n</i>.<tt>name</tt><br> |
---|
57 | <font size=-1>String</font></td> |
---|
58 | <td valign=top>(name of rule set constraint <i>n</i>)</td></tr> |
---|
59 | |
---|
60 | <tr><td valign=top><i>base.n</i>.<tt>reset-min-size</tt><br> |
---|
61 | <font size=-1>int >= 0 (default=0)</font></td> |
---|
62 | <td valign=top>(for rule set constraint <i>n</i>, the minimum number of rules that rulesets may contain upon initialization (resetting), see discussion above)</td></tr> |
---|
63 | |
---|
64 | <tr><td valign=top><i>base.n</i>.<tt>reset-max-size</tt><br> |
---|
65 | <font size=-1>int >= <i>base.n</i>.<tt>reset-min-size</tt> (default=0)</font></td> |
---|
66 | <td valign=top>(for rule set constraint <i>n</i>, the maximum number of rules that rulesets may contain upon initialization (resetting), see discussion above)</td></tr> |
---|
67 | |
---|
68 | <tr><td valign=top><i>base.n</i>.<tt>reset-num-sizes</tt><br> |
---|
69 | <font size=-1>int >= 0</font> (default=unset)</td> |
---|
70 | <td valign=top>(for rule set constraint <i>n</i>, the number of sizes in the size distribution for initializtion, see discussion above)</td></tr> |
---|
71 | |
---|
72 | <tr><td valign=top><i>base.n</i>.<tt>reset-size</tt>.<i>i</i><br> |
---|
73 | <font size=-1>0.0 <= float <= 1.0</font></td> |
---|
74 | <td valign=top>(for rule set constraint <i>n</i>, the probability that <i>i</i> will be chosen as the number of rules upon initialization, see discussion above)</td></tr> |
---|
75 | |
---|
76 | <tr><td valign=top><i>base.n</i>.<tt>p-add</tt><br> |
---|
77 | <font size=-1>0.0 <= float <= 1.0</font></td> |
---|
78 | <td valign=top>(the probability that a new rule will be added, see discussion)</td></tr> |
---|
79 | |
---|
80 | <tr><td valign=top><i>base.n</i>.<tt>p-del</tt><br> |
---|
81 | <font size=-1>0.0 <= float <= 1.0</font></td> |
---|
82 | <td valign=top>(the probability that a rule will be deleted, see discussion)</td></tr> |
---|
83 | |
---|
84 | <tr><td valign=top><i>base.n</i>.<tt>p-rand-order</tt><br> |
---|
85 | <font size=-1>0.0 <= float <= 1.0</font></td> |
---|
86 | <td valign=top>(the probability that the rules' order will be randomized, see discussion)</td></tr> |
---|
87 | </table> |
---|
88 | |
---|
89 | */ |
---|
90 | public class RuleSetConstraints implements Clique |
---|
91 | { |
---|
92 | /** The size of a byte */ |
---|
93 | // public static final int SIZE_OF_BYTE = 256; |
---|
94 | public final static String P_NAME = "name"; |
---|
95 | /** num rulesets */ |
---|
96 | // public final static String P_SIZE = "size"; |
---|
97 | public final static String P_RULE = "rule"; // our prototype |
---|
98 | // public static final int CHECK_BOUNDARY = 8; |
---|
99 | public static final String P_RESETMINSIZE = "reset-min-size"; |
---|
100 | public static final String P_RESETMAXSIZE = "reset-max-size"; |
---|
101 | public static final String P_NUMSIZES = "reset-num-sizes"; |
---|
102 | public static final String P_RESETSIZE = "reset-size"; |
---|
103 | |
---|
104 | public static final String P_MINSIZE = "min-size"; |
---|
105 | public static final String P_MAXSIZE = "max-size"; |
---|
106 | |
---|
107 | public int minSize; // the minimum legal size |
---|
108 | public int maxSize; // the maximum legal size |
---|
109 | |
---|
110 | public int resetMinSize; // the minium possible size -- if unused, it's 0, but 0 is also a valid number, so check sizeDistribution==null |
---|
111 | public int resetMaxSize; // the maximum possible size -- if unused, it's 0, but 0 is also a valid number, so check sizeDistribution==null |
---|
112 | public float[] sizeDistribution; |
---|
113 | |
---|
114 | // probability of adding a random rule to the rule set |
---|
115 | public static final String P_ADD_PROB = "p-add"; |
---|
116 | public float p_add; |
---|
117 | |
---|
118 | // probability of removing a random rule from the rule set |
---|
119 | public static final String P_DEL_PROB = "p-del"; |
---|
120 | public float p_del; |
---|
121 | |
---|
122 | // probability of randomizing the rule order in the rule set |
---|
123 | public static final String P_RAND_ORDER_PROB = "p-rand-order"; |
---|
124 | public float p_randorder; |
---|
125 | |
---|
126 | /** Assuming that either resetMinSize and resetMaxSize, or sizeDistribution, is defined, |
---|
127 | picks a random size from resetMinSize...resetMaxSize inclusive, or randomly |
---|
128 | from sizeDistribution. */ |
---|
129 | public int pickSize(final EvolutionState state, final int thread) |
---|
130 | { |
---|
131 | if (sizeDistribution!=null) |
---|
132 | // pick from distribution |
---|
133 | return RandomChoice.pickFromDistribution( |
---|
134 | sizeDistribution, |
---|
135 | state.random[thread].nextFloat()); |
---|
136 | else |
---|
137 | // pick from resetMinSize...resetMaxSize |
---|
138 | return state.random[thread].nextInt(resetMaxSize-resetMinSize+1) + resetMinSize; |
---|
139 | } |
---|
140 | |
---|
141 | /** |
---|
142 | The prototype of the Rule that will be used in the RuleSet |
---|
143 | (the RuleSet contains only rules with the specified prototype). |
---|
144 | */ |
---|
145 | public Rule rulePrototype; |
---|
146 | |
---|
147 | /** |
---|
148 | Returns a stochastic value picked to specify the number of rules |
---|
149 | to generate when calling reset() on this kind of Rule. The default |
---|
150 | version picks from the min/max or distribution, but you can override |
---|
151 | this to do whatever kind of thing you like here. |
---|
152 | */ |
---|
153 | public int numRulesForReset(final RuleSet ruleset, |
---|
154 | final EvolutionState state, final int thread) |
---|
155 | { |
---|
156 | // the default just uses pickSize |
---|
157 | return pickSize(state,thread); |
---|
158 | } |
---|
159 | |
---|
160 | /** The byte value of the constraints -- we can only have 256 of them */ |
---|
161 | public byte constraintNumber; |
---|
162 | |
---|
163 | /** The name of the RuleSetConstraints object */ |
---|
164 | public String name; |
---|
165 | |
---|
166 | /** Converting the rule to a string ( the name ) */ |
---|
167 | public String toString() { return name; } |
---|
168 | |
---|
169 | /** Sets up all the RuleSetConstraints, loading them from the parameter |
---|
170 | file. This must be called before anything is called which refers |
---|
171 | to a type by name. */ |
---|
172 | |
---|
173 | /** You must guarantee that after calling constraintsFor(...) one or |
---|
174 | several times, you call state.output.exitIfErrors() once. */ |
---|
175 | |
---|
176 | public static RuleSetConstraints constraintsFor(final String constraintsName, |
---|
177 | final EvolutionState state) |
---|
178 | { |
---|
179 | RuleSetConstraints myConstraints = (RuleSetConstraints)(((RuleInitializer)state.initializer).ruleSetConstraintRepository.get(constraintsName)); |
---|
180 | if (myConstraints==null) |
---|
181 | state.output.error("The rule constraints \"" + constraintsName + "\" could not be found."); |
---|
182 | return myConstraints; |
---|
183 | } |
---|
184 | |
---|
185 | |
---|
186 | public void setup(final EvolutionState state, final Parameter base) |
---|
187 | { |
---|
188 | // What's my name? |
---|
189 | name = state.parameters.getString(base.push(P_NAME),null); |
---|
190 | if (name==null) |
---|
191 | state.output.fatal("No name was given for this RuleSetConstraints.", |
---|
192 | base.push(P_NAME)); |
---|
193 | |
---|
194 | // Register me |
---|
195 | RuleSetConstraints old_constraints = (RuleSetConstraints)(((RuleInitializer)state.initializer).ruleSetConstraintRepository.put(name,this)); |
---|
196 | if (old_constraints != null) |
---|
197 | state.output.fatal("The rule constraints \"" + name + "\" has been defined multiple times.", base.push(P_NAME)); |
---|
198 | |
---|
199 | // load my prototypical Rule |
---|
200 | rulePrototype = (Rule)(state.parameters.getInstanceForParameter(base.push(P_RULE),null,Rule.class)); |
---|
201 | rulePrototype.setup(state,base.push(P_RULE)); |
---|
202 | |
---|
203 | p_add = state.parameters.getFloat( base.push( P_ADD_PROB ), null, 0 ); |
---|
204 | if( p_add < 0 || p_add > 1 ) |
---|
205 | { |
---|
206 | state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].", |
---|
207 | base.push( P_ADD_PROB ) ); |
---|
208 | } |
---|
209 | p_del = state.parameters.getFloat( base.push( P_DEL_PROB ), null, 0 ); |
---|
210 | if( p_del < 0 || p_del > 1 ) |
---|
211 | { |
---|
212 | state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].", |
---|
213 | base.push( P_DEL_PROB ) ); |
---|
214 | } |
---|
215 | |
---|
216 | p_randorder = state.parameters.getFloat( base.push( P_RAND_ORDER_PROB ), null, 0 ); |
---|
217 | if( p_randorder < 0 || p_randorder > 1 ) |
---|
218 | { |
---|
219 | state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].", |
---|
220 | base.push( P_RAND_ORDER_PROB ) ); |
---|
221 | } |
---|
222 | |
---|
223 | // now, we are going to load EITHER min/max size OR a size distribution, or both |
---|
224 | // (the size distribution takes precedence) |
---|
225 | |
---|
226 | // reset min and max size |
---|
227 | |
---|
228 | if (state.parameters.exists(base.push(P_RESETMINSIZE), null) || |
---|
229 | state.parameters.exists(base.push(P_RESETMAXSIZE), null)) |
---|
230 | { |
---|
231 | if (!(state.parameters.exists(base.push(P_RESETMAXSIZE), null))) |
---|
232 | state.output.error("This RuleSetConstraints has a " + |
---|
233 | P_RESETMINSIZE + " but not a " + P_RESETMAXSIZE + "."); |
---|
234 | |
---|
235 | resetMinSize = state.parameters.getInt( |
---|
236 | base.push(P_RESETMINSIZE), null,0); |
---|
237 | if (resetMinSize==-1) |
---|
238 | state.output.error("If min&max are defined, RuleSetConstraints must have a min size >= 0.", |
---|
239 | base.push(P_RESETMINSIZE), null); |
---|
240 | |
---|
241 | resetMaxSize = state.parameters.getInt( |
---|
242 | base.push(P_RESETMAXSIZE), null,0); |
---|
243 | if (resetMaxSize==-1) |
---|
244 | state.output.error("If min&max are defined, RuleSetConstraints must have a max size >= 0.", |
---|
245 | base.push(P_RESETMAXSIZE), null); |
---|
246 | |
---|
247 | if (resetMinSize > resetMaxSize) |
---|
248 | state.output.error( |
---|
249 | "If min&max are defined, RuleSetConstraints must have min size <= max size.", |
---|
250 | base.push(P_RESETMINSIZE), null); |
---|
251 | state.output.exitIfErrors(); |
---|
252 | } |
---|
253 | |
---|
254 | // load sizeDistribution |
---|
255 | |
---|
256 | if (state.parameters.exists(base.push(P_NUMSIZES), |
---|
257 | null)) |
---|
258 | { |
---|
259 | int siz = state.parameters.getInt( |
---|
260 | base.push(P_NUMSIZES), null,1); |
---|
261 | if (siz==0) |
---|
262 | state.output.fatal("The number of sizes in the RuleSetConstraints's distribution must be >= 1. "); |
---|
263 | sizeDistribution = new float[siz]; |
---|
264 | |
---|
265 | float sum = 0.0f; |
---|
266 | for(int x=0;x<siz;x++) |
---|
267 | { |
---|
268 | sizeDistribution[x] = state.parameters.getFloat( |
---|
269 | base.push(P_RESETSIZE).push(""+x),null, 0.0f); |
---|
270 | if (sizeDistribution[x]<0.0) |
---|
271 | { |
---|
272 | state.output.warning( |
---|
273 | "Distribution value #" + x + " negative or not defined, assumed to be 0.0", |
---|
274 | base.push(P_RESETSIZE).push(""+x),null); |
---|
275 | sizeDistribution[x] = 0.0f; |
---|
276 | } |
---|
277 | sum += sizeDistribution[x]; |
---|
278 | } |
---|
279 | if (sum>1.0) |
---|
280 | state.output.warning( |
---|
281 | "Distribution sums to greater than 1.0", |
---|
282 | base.push(P_RESETSIZE), |
---|
283 | null); |
---|
284 | if (sum==0.0) |
---|
285 | state.output.fatal( |
---|
286 | "Distribution is all 0's", |
---|
287 | base.push(P_RESETSIZE), |
---|
288 | null); |
---|
289 | |
---|
290 | // normalize and prepare |
---|
291 | RandomChoice.organizeDistribution(sizeDistribution); |
---|
292 | } |
---|
293 | |
---|
294 | if (state.parameters.exists(base.push(P_MINSIZE), null)) |
---|
295 | minSize = state.parameters.getInt( base.push( P_MINSIZE ), null, 0 ); |
---|
296 | else minSize = 0; |
---|
297 | |
---|
298 | if (state.parameters.exists(base.push(P_MAXSIZE), null)) |
---|
299 | maxSize = state.parameters.getInt( base.push( P_MAXSIZE ), null, 0 ); |
---|
300 | else maxSize = Integer.MAX_VALUE; |
---|
301 | |
---|
302 | // sanity checks |
---|
303 | if (minSize > maxSize) |
---|
304 | { |
---|
305 | state.output.fatal("Cannot have min size greater than max size : (" + minSize + " > " + maxSize + ")",base.push(P_MINSIZE), null); |
---|
306 | } |
---|
307 | |
---|
308 | if (sizeDistribution != null) |
---|
309 | { |
---|
310 | if (minSize!=0) |
---|
311 | state.output.fatal("Using size distribution, but min size is not 0", |
---|
312 | base.push(P_MINSIZE), null); |
---|
313 | if (sizeDistribution.length - 1 > maxSize) |
---|
314 | state.output.fatal("Using size distribution whose maximum size is higher than max size", |
---|
315 | base.push(P_MAXSIZE), null); |
---|
316 | } |
---|
317 | else |
---|
318 | { |
---|
319 | if (resetMinSize < minSize) |
---|
320 | state.output.fatal("Cannot have min size greater than reset min size : (" + minSize + " > " + resetMinSize + ")",base.push(P_MINSIZE), null); |
---|
321 | if (resetMaxSize > maxSize) |
---|
322 | state.output.fatal("Cannot have max size less than reset max size : (" + maxSize + " > " + resetMaxSize + ")",base.push(P_MAXSIZE), null); |
---|
323 | } |
---|
324 | |
---|
325 | } |
---|
326 | } |
---|
327 | |
---|