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);
}
}
}