// Sc = type of scores (e.g. Double) sclass TunableParameters> { replace Scrd with GenericallyScored. settable IF1 scoreFunction; gettable Scrd best; new LinkedHashMap parameters; new L parameterList; gettable volatile long instancesTested; event newBest(Scrd instance); event fireInstanceScored(Scrd scored); abstract class Parameter { settable S name; settable A defaultValue; abstract A randomValue(); A get(MapSO instance) { ret (A) instance.get(name); } } class IntRangeParameter extends Parameter { settable IntRange range; Int randomValue() { ret random(range); } } class DoubleRangeParameter extends Parameter { settable DoubleRange range; Double randomValue() { ret random(range); } } selfType add(Parameter p) { parameters.put(p.name(), p); parameterList.add(p); this; } MapSO randomInstance() { MapSO map = new LinkedHashMap; for (param : parameterList) map.put(param.name(), param.randomValue()); ret map; } Scrd tryARandomCombination() { ret tryInstance(randomInstance()); } 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; ret scoreFunction.get(instance); } Scrd scored(MapSO instance) { Scrd scored = new GenericallyScored<>(instance, score(instance)); fireInstanceScored(scored); ret scored; } Scrd tryInstance(MapSO instance) { Scrd scored = scored(instance); tryInstance(scored); ret scored; } void tryInstance(Scrd scored) { if (scored == null) ret; if (best == null || cmp(scored.score(), best.score()) > 0) { best = scored; newBest(scored); } } toString { ret "Best: " + best + " (parameters: " + keys(parameters) + ")"; } }