/* Copyright 2006 by Sean Luke and George Mason University Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package ec.rule; import ec.*; import ec.util.*; /* * RuleSetConstraints.java * * Created: Tue Feb 20 13:26:00 2001 * By: Liviu Panait and Sean Luke */ /** * RuleSetConstraints is an basic class for constraints applicable to rulesets. * There are two categories of parameters associated with this class. First, there are parameters * which guide the initial number of rules to be created when a ruleset is initialized for * the first time, or totally reset. Second, there are parameters which indicate how rulesets * are to be mutated under the "default" rule mutation operator. * *

First the initialization parameters. You need to specify a distribution from which * the system will pick random integer values X. When a ruleset is to be initialized, a * random value X is picked from this distribution, and the ruleset will be created with X initial rules. * You can specify the distribution in one of two ways. First, you can specify a minimum and maximum * number of rules; the system will then pick an X uniformly from between the min and the max. * Second, you can specify a full distribution of size probabilities for more control. For example, * to specify that the system should make individuals with 0 rules 0.1 of the time, 1 rule 0.2 of the time, * and 2 rules 0.7 of the time, you set reset-num-sizes to 3 (for rule sizes up to but not including 3), * and then set reset-size.0 to 0.1, reset-size.1 to 0.2, and reset-size.2 to 0.7. * *

Next the mutation parameters. The default mutation procedure works as follows. First, every rule * in the ruleset is mutated. It is up to the rule to determine by how much or whether it will be mutated * (perhaps by flipping a coin) when its mutate function is called. Second, the system repeatedly flips * a coin with "p-del" probability of being true, until it comes up false. The number of times it came up * true is the number of rules to remove from the ruleset; rules to be removed are chosen at random. * Third, the system repeatedly flips * a coin with "p-add" probability of being true, until it comes up false. The number of times it came up * true is the number of new randomly-generated rules to add to the ruleset; rules are added to the end of the array. * Fourth, with "p-rand-order" probability, the order of rules in the ruleset array is randomized; this last * item might or might not matter to you depending on whether or not your rule interpreter differs depending on rule order. * * @author Liviu Panait and Sean Luke * @version 1.0

Parameters
base.size
int >= 1
(number of rule set constraints)
base.n.name
String
(name of rule set constraint n)
base.n.reset-min-size
int >= 0 (default=0)
(for rule set constraint n, the minimum number of rules that rulesets may contain upon initialization (resetting), see discussion above)
base.n.reset-max-size
int >= base.n.reset-min-size (default=0)
(for rule set constraint n, the maximum number of rules that rulesets may contain upon initialization (resetting), see discussion above)
base.n.reset-num-sizes
int >= 0 (default=unset)
(for rule set constraint n, the number of sizes in the size distribution for initializtion, see discussion above)
base.n.reset-size.i
0.0 <= float <= 1.0
(for rule set constraint n, the probability that i will be chosen as the number of rules upon initialization, see discussion above)
base.n.p-add
0.0 <= float <= 1.0
(the probability that a new rule will be added, see discussion)
base.n.p-del
0.0 <= float <= 1.0
(the probability that a rule will be deleted, see discussion)
base.n.p-rand-order
0.0 <= float <= 1.0
(the probability that the rules' order will be randomized, see discussion)
*/ public class RuleSetConstraints implements Clique { /** The size of a byte */ // public static final int SIZE_OF_BYTE = 256; public final static String P_NAME = "name"; /** num rulesets */ // public final static String P_SIZE = "size"; public final static String P_RULE = "rule"; // our prototype // public static final int CHECK_BOUNDARY = 8; public static final String P_RESETMINSIZE = "reset-min-size"; public static final String P_RESETMAXSIZE = "reset-max-size"; public static final String P_NUMSIZES = "reset-num-sizes"; public static final String P_RESETSIZE = "reset-size"; public static final String P_MINSIZE = "min-size"; public static final String P_MAXSIZE = "max-size"; public int minSize; // the minimum legal size public int maxSize; // the maximum legal size public int resetMinSize; // the minium possible size -- if unused, it's 0, but 0 is also a valid number, so check sizeDistribution==null public int resetMaxSize; // the maximum possible size -- if unused, it's 0, but 0 is also a valid number, so check sizeDistribution==null public float[] sizeDistribution; // probability of adding a random rule to the rule set public static final String P_ADD_PROB = "p-add"; public float p_add; // probability of removing a random rule from the rule set public static final String P_DEL_PROB = "p-del"; public float p_del; // probability of randomizing the rule order in the rule set public static final String P_RAND_ORDER_PROB = "p-rand-order"; public float p_randorder; /** Assuming that either resetMinSize and resetMaxSize, or sizeDistribution, is defined, picks a random size from resetMinSize...resetMaxSize inclusive, or randomly from sizeDistribution. */ public int pickSize(final EvolutionState state, final int thread) { if (sizeDistribution!=null) // pick from distribution return RandomChoice.pickFromDistribution( sizeDistribution, state.random[thread].nextFloat()); else // pick from resetMinSize...resetMaxSize return state.random[thread].nextInt(resetMaxSize-resetMinSize+1) + resetMinSize; } /** The prototype of the Rule that will be used in the RuleSet (the RuleSet contains only rules with the specified prototype). */ public Rule rulePrototype; /** Returns a stochastic value picked to specify the number of rules to generate when calling reset() on this kind of Rule. The default version picks from the min/max or distribution, but you can override this to do whatever kind of thing you like here. */ public int numRulesForReset(final RuleSet ruleset, final EvolutionState state, final int thread) { // the default just uses pickSize return pickSize(state,thread); } /** The byte value of the constraints -- we can only have 256 of them */ public byte constraintNumber; /** The name of the RuleSetConstraints object */ public String name; /** Converting the rule to a string ( the name ) */ public String toString() { return name; } /** Sets up all the RuleSetConstraints, loading them from the parameter file. This must be called before anything is called which refers to a type by name. */ /** You must guarantee that after calling constraintsFor(...) one or several times, you call state.output.exitIfErrors() once. */ public static RuleSetConstraints constraintsFor(final String constraintsName, final EvolutionState state) { RuleSetConstraints myConstraints = (RuleSetConstraints)(((RuleInitializer)state.initializer).ruleSetConstraintRepository.get(constraintsName)); if (myConstraints==null) state.output.error("The rule constraints \"" + constraintsName + "\" could not be found."); return myConstraints; } public void setup(final EvolutionState state, final Parameter base) { // What's my name? name = state.parameters.getString(base.push(P_NAME),null); if (name==null) state.output.fatal("No name was given for this RuleSetConstraints.", base.push(P_NAME)); // Register me RuleSetConstraints old_constraints = (RuleSetConstraints)(((RuleInitializer)state.initializer).ruleSetConstraintRepository.put(name,this)); if (old_constraints != null) state.output.fatal("The rule constraints \"" + name + "\" has been defined multiple times.", base.push(P_NAME)); // load my prototypical Rule rulePrototype = (Rule)(state.parameters.getInstanceForParameter(base.push(P_RULE),null,Rule.class)); rulePrototype.setup(state,base.push(P_RULE)); p_add = state.parameters.getFloat( base.push( P_ADD_PROB ), null, 0 ); if( p_add < 0 || p_add > 1 ) { state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].", base.push( P_ADD_PROB ) ); } p_del = state.parameters.getFloat( base.push( P_DEL_PROB ), null, 0 ); if( p_del < 0 || p_del > 1 ) { state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].", base.push( P_DEL_PROB ) ); } p_randorder = state.parameters.getFloat( base.push( P_RAND_ORDER_PROB ), null, 0 ); if( p_randorder < 0 || p_randorder > 1 ) { state.output.fatal( "Parameter not found, or its value is outside of allowed range [0..1].", base.push( P_RAND_ORDER_PROB ) ); } // now, we are going to load EITHER min/max size OR a size distribution, or both // (the size distribution takes precedence) // reset min and max size if (state.parameters.exists(base.push(P_RESETMINSIZE), null) || state.parameters.exists(base.push(P_RESETMAXSIZE), null)) { if (!(state.parameters.exists(base.push(P_RESETMAXSIZE), null))) state.output.error("This RuleSetConstraints has a " + P_RESETMINSIZE + " but not a " + P_RESETMAXSIZE + "."); resetMinSize = state.parameters.getInt( base.push(P_RESETMINSIZE), null,0); if (resetMinSize==-1) state.output.error("If min&max are defined, RuleSetConstraints must have a min size >= 0.", base.push(P_RESETMINSIZE), null); resetMaxSize = state.parameters.getInt( base.push(P_RESETMAXSIZE), null,0); if (resetMaxSize==-1) state.output.error("If min&max are defined, RuleSetConstraints must have a max size >= 0.", base.push(P_RESETMAXSIZE), null); if (resetMinSize > resetMaxSize) state.output.error( "If min&max are defined, RuleSetConstraints must have min size <= max size.", base.push(P_RESETMINSIZE), null); state.output.exitIfErrors(); } // load sizeDistribution if (state.parameters.exists(base.push(P_NUMSIZES), null)) { int siz = state.parameters.getInt( base.push(P_NUMSIZES), null,1); if (siz==0) state.output.fatal("The number of sizes in the RuleSetConstraints's distribution must be >= 1. "); sizeDistribution = new float[siz]; float sum = 0.0f; for(int x=0;x1.0) state.output.warning( "Distribution sums to greater than 1.0", base.push(P_RESETSIZE), null); if (sum==0.0) state.output.fatal( "Distribution is all 0's", base.push(P_RESETSIZE), null); // normalize and prepare RandomChoice.organizeDistribution(sizeDistribution); } if (state.parameters.exists(base.push(P_MINSIZE), null)) minSize = state.parameters.getInt( base.push( P_MINSIZE ), null, 0 ); else minSize = 0; if (state.parameters.exists(base.push(P_MAXSIZE), null)) maxSize = state.parameters.getInt( base.push( P_MAXSIZE ), null, 0 ); else maxSize = Integer.MAX_VALUE; // sanity checks if (minSize > maxSize) { state.output.fatal("Cannot have min size greater than max size : (" + minSize + " > " + maxSize + ")",base.push(P_MINSIZE), null); } if (sizeDistribution != null) { if (minSize!=0) state.output.fatal("Using size distribution, but min size is not 0", base.push(P_MINSIZE), null); if (sizeDistribution.length - 1 > maxSize) state.output.fatal("Using size distribution whose maximum size is higher than max size", base.push(P_MAXSIZE), null); } else { if (resetMinSize < minSize) state.output.fatal("Cannot have min size greater than reset min size : (" + minSize + " > " + resetMinSize + ")",base.push(P_MINSIZE), null); if (resetMaxSize > maxSize) state.output.fatal("Cannot have max size less than reset max size : (" + maxSize + " > " + resetMaxSize + ")",base.push(P_MAXSIZE), null); } } }