package bsearch.space; import org.nlogo.api.LogoList; import org.nlogo.util.MersenneTwisterFast; /** * Note: the Objects need to be types that NetLogo understands * (e.g. Double, String, LogoList, Boolean...) */ public strictfp abstract class ParameterSpec { String name; public ParameterSpec(String name) { this.name = name; } public String getParameterName() { return name; } public abstract Object generateRandomValue(MersenneTwisterFast rng); public abstract Object mutate(Object obj, double mutStrength, MersenneTwisterFast rng); public abstract Object getValueFromChoice(long choice, long maxNumChoices); public abstract long getChoiceIndexFromValue(Object val, long maxNumChoices); /** * The special value -1 indicates a continuous parameter. */ public abstract int choiceCount(); // public abstract Object enforceValid(Object obj1); //TODO: Hmm, for BITSTRING type, we could do crossover at the gene level too. //public abstract T crossover(T obj1, T obj2, MersenneTwisterFast rng); /** * Takes a textual parameter specification, and gives back an appropriate ParameterSpec object * @param paramString */ public static ParameterSpec fromString(String paramString) { try { Object obj = bsearch.nlogolink.Utils.evaluateNetLogoReporterInEmptyWorkspace(paramString); if (obj instanceof LogoList) { LogoList lst = (LogoList) obj; String name = (String) lst.get( 0 ); obj = lst.get(1); if (obj instanceof LogoList) // ranged specification { LogoList innerLst = (LogoList) obj; if (innerLst.size() != 3) { throw new IllegalArgumentException("Invalid parameter range spec: " + paramString); } Double dMin = (Double) innerLst.get( 0 ); Object incr = innerLst.get( 1 ); if (incr instanceof Double) // discrete step size { Double dStep = (Double) incr; Double dMax = (Double) innerLst.get( 2 ); return new DoubleDiscreteSpec(name, dMin, dStep, dMax) ; } else if (incr.toString().equals( "C" )) // continuous step size { Double dMax = (Double) innerLst.get( 2 ); return new DoubleContinuousSpec(name, dMin, dMax) ; } else { throw new IllegalArgumentException("Invalid ranged parameter spec, increment must be either \"C\" or a number. " + paramString); } } else // discrete list of items { if (lst.size() > 2) { return new CategoricalSpec(name, lst.butFirst()); } else { return new ConstantSpec(name, lst.get(1)); } } } else { throw new IllegalArgumentException("Invalid parameter spec: " + paramString + " | Object=" + obj ); } } catch (Exception ex) { if (ex instanceof IllegalArgumentException) { throw (IllegalArgumentException) ex; } //TODO: Better error messages? throw new IllegalArgumentException("Invalid parameter range spec: " + paramString + ". Error was " + ex.getMessage(), ex); } } }