package parameterrules; import java.io.*; import main.BetterTokenizer; import parameters.Parameter; import parameters.ParameterSet; import main.GeneralInput; import main.MoreMath; import affectors.Affector; public class ParameterRule implements Cloneable { /** The reference parameter set, used to figure out the positions of parameters that are used by this rule. You should initialize the reference parameter (using the init() method) before setting the parameters of the rule */ ParameterSet refParams; protected int [] paramNums = new int[5]; protected int numParams = 0; ParameterRule() {} /** Initializes refParam to point to a parameter set which will be used as reference herein. Usually the rule should be initialized with the parameter set of an iterator. Only override this if there is some special initialization required by a sub-class. */ public void init(ParameterSet params) { refParams = params; } public ParameterRule copy() { ParameterRule pr = null; try { pr = (ParameterRule)this.clone(); } catch(CloneNotSupportedException e) {} pr.paramNums = new int[numParams]; System.arraycopy(paramNums, 0, pr.paramNums, 0, numParams); return pr; } /** Returns true if the parameters in the input set meet the criteria for this rule, false otherwise. The default implementation calls getFuzzyScore() and returns true if the value was <= 0, false otherwise. Most parameter rules should only override getFuzzyScore and leave getGood() alone. @param params The values of all the parameters in the reference parameter set. The params array and the reference parameter set need to match one-to-one. */ public boolean isGood(float [] params) { return (getFuzzyScore(params) <= 0); } /** This method should return 0 if the parameters in the input set pass the criteria in this rule. Otherwise it should return a positive number whose magnitude gets larger as the parameter set gets farther from satisfying this rule. @param params The values of all the parameters in the reference parameter set. The params array and the reference parameter set need to match one-to-one. */ public float getFuzzyScore(float [] params) { return 0; } /** This method should change parameters so that they conform to this rule. If the parameters matched the rule without any changes, this method should return true. Otherwise, return false. @param params The values of all the parameters in the reference parameter set. The params array and the reference parameter set need to match one-to-one. */ public boolean changeParameters(float [] params, int mode, ParameterSet set) { System.out.println("Change Parameters not yet implemented for one of the parameter rules"); return isGood(params); } /** Picks a new parameter value in the range min to max. Both min and max are checked against the standard range for this parameter and adjusted if neccesary. The method picks from either a linear or logarithmic distribution as appropriate for that parameter. This basically encapsulates picking a new value for a parameter in a way that many (but perhaps not all) parameter rules can use rather than rewriting the code each time.
Note that change_param is an index into paramNums, not an index directly to lists of parameters. */ protected void pickNewParameterValue(float [] params, int change_param, float min, float max, int mode, ParameterSet set) { //int param_pos = paramNums[change_param]; int param_pos = change_param; if(min < set.getLowerBound(param_pos)) min = set.getLowerBound(param_pos); if(max > set.getUpperBound(param_pos)) max = set.getUpperBound(param_pos); // Pick a value if(min < max) { if(mode == MoreMath.UNIFORM) { int var_mode = set.getVariationMode(param_pos); if(var_mode == Parameter.LOGARITHMIC) params[param_pos] = MoreMath.pickRandomLogarithmic(min, max); else params[param_pos] = MoreMath.pickRandomLinear(min, max); } else System.out.println("ParameterRule doesn't know how to do Gaussian random picks"); } else if(min == max) params[param_pos] = min; // else nothing we can do //Put this line in if want printout each time rule changes a value System.out.println("New value for " + set.getName(param_pos) + ": [" + min + "," + max + "] = " + params[param_pos]); } /** The main method for loading paramaters from a stream. You shouldn't ever need to change this. Instead, override loadParameter */ public void loadParameters(BetterTokenizer tokenizer) throws Exception { GeneralInput.indent++; String info = GeneralInput.findNextIDToken(tokenizer); while(!info.equals("endPR")) { loadParameter(info, tokenizer); info = GeneralInput.findNextIDToken(tokenizer); } GeneralInput.indent--; } /** Override this function for each parameter rule to load in setup info specific to that rule. You can use the refParam to look up the positions of any model parameters you load. The default method will load parameters with the @Param tag and put the parameter numbers into the paramNums array. */ protected void loadParameter(String info, BetterTokenizer tokenizer) throws Exception { if(info.equals("Param")) { if(numParams == paramNums.length) { // Expand array length int [] temp = new int[paramNums.length + 5]; System.arraycopy(paramNums, 0, temp, 0, numParams); paramNums = temp; } GeneralInput.nextToken(tokenizer); paramNums[numParams] = refParams.getPosition(tokenizer.sval); // Should throw exception if param doesn't exist numParams++; } } }