// Sc = type of scores (e.g. Double) // Sc can also be the actual instance created (e.g. a strategy) // If Sc is not Comparable, you can supply an additional // comparisonFunction. sclass TunableParameters { //replace Scrd with GenericallyScored. class Scrd extends Var { gettable Sc score; *() {} *(MapSO a, Sc score) { super(a); this.score = score; } toString { ret actualScoreFunction.get(score) + ": " + str(get()); } bool isBest() { ret this == best; } bool tiesBest() { ret compareScrd(this, best) == 0; } O actualScore() { ret actualScoreFunction.get(score); } } settable IF1 scoreFunction; settable IF2_OOInt comparisonFunction; settable IF1 actualScoreFunction = l1 id; gettable Scrd best; new LinkedHashMap parameters; new L parameterList; gettable volatile long instancesTested; event testingInstance(MapSO instance); event fireInstanceScored(Scrd scored); event newBest(Scrd instance); abstract class Parameter { settable S name; settable A defaultValue; abstract A randomValue(); A get(MapSO instance) { ret (A) instance.get(name); } TunableParameters tuner() { ret TunableParameters.this; } } class IntRangeParameter extends Parameter { settable IntRange range; settable int step = 1; Int randomValue() { ret random(range); } selfType fixedValue(int value) { defaultValue(value); range(intRange(value, value)); this; } } class DoubleRangeParameter extends Parameter { settable DoubleRange range; settable double step = .1; Double randomValue() { ret random(range); } selfType fixedValue(double value) { defaultValue(value); range(doubleRange(value, value)); this; } } A add(A p) { parameters.put(p.name(), p); parameterList.add(p); ret p; } IntRangeParameter intParam(S name, int defaultValue, int min, int max) { new IntRangeParameter p; p.range(intRange(min, max)).+defaultValue.+name; ret add(p); } DoubleRangeParameter doubleParam(S name, double defaultValue, double min, double max, double step default .1) { new DoubleRangeParameter p; p.range(doubleRange(min, max)).+step.+defaultValue.+name; ret add(p); } MapSO randomInstance() { MapSO map = new LinkedHashMap; for (param : parameterList) map.put(param.name(), param.randomValue()); ret map; } MapSO defaultInstance() { MapSO map = new LinkedHashMap; for (param : parameterList) map.put(param.name(), param.defaultValue()); ret map; } Scrd tryARandomCombination() { ret tryInstance(randomInstance()); } Scrd tryDefaultValues() { ret tryInstance(defaultInstance()); } // replaces the parameter with a random value L varyEachParameterOnce(MapSO instance) { if (instance == null) null; new L out; for (param : parameterList) { O value = param.randomValue(); if (eq(param.get(instance), value)) continue; MapSO instance2 = cloneMap(instance); instance2.put(param.name(), value); out.add(tryInstance(instance2)); } ret out; } Sc score(MapSO instance) { ++instancesTested; testingInstance(instance); ret scoreFunction.get(instance); } Scrd scored(MapSO instance) { Scrd scored = new(instance, score(instance)); fireInstanceScored(scored); ret scored; } Scrd tryInstance(MapSO instance) { if (instance == null) null; Scrd scored = scored(instance); tryInstance(scored); ret scored; } void tryInstance(Scrd scored) { if (scored == null) ret; if (best == null || compareScrd(scored, best) > 0) { best = scored; newBest(scored); } } int compareScrd(Scrd a, Scrd b) { Sc scoreA = a.score(); Sc scoreB = b.score(); ret comparisonFunction == null ? cmp(scoreA, scoreB) : comparisonFunction.get(actualScoreFunction.get(scoreA), actualScoreFunction.get(scoreB)); } toString { ret "Best: " + best + " (parameters: " + keys(parameters) + ")"; } MapSO bestOrDefaultInstance() { if (best == null) tryDefaultValues(); ret best!; } }