diff --git a/pom.xml b/pom.xml
index 52106efb..ee9496c2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,27 +27,6 @@
javahelp
2.0.05
-
- org.apache.commons
- commons-math3
- 3.1.1
-
-
- commons-cli
- commons-cli
- 1.2
-
-
- com.google.code.gson
- gson
- 2.3
- compile
-
-
- org.reflections
- reflections
- 0.9.9
-
diff --git a/src/eva2/cli/Main.java b/src/eva2/cli/Main.java
index b951db4b..4d2e3308 100644
--- a/src/eva2/cli/Main.java
+++ b/src/eva2/cli/Main.java
@@ -1,719 +1,15 @@
package eva2.cli;
-import com.google.gson.*;
-import eva2.OptimizerFactory;
-import eva2.optimization.OptimizationStateListener;
-import eva2.optimization.enums.DEType;
-import eva2.optimization.enums.PSOTopology;
-import eva2.optimization.population.InterfacePopulationChangedEventListener;
-import eva2.optimization.modules.OptimizationParameters;
-import eva2.optimization.operator.crossover.CrossoverESDefault;
-import eva2.optimization.operator.crossover.InterfaceCrossover;
-import eva2.optimization.operator.mutation.InterfaceMutation;
-import eva2.optimization.operator.mutation.MutateDefault;
-import eva2.optimization.operator.selection.InterfaceSelection;
-import eva2.optimization.operator.selection.SelectXProbRouletteWheel;
-import eva2.optimization.operator.terminators.CombinedTerminator;
-import eva2.optimization.operator.terminators.FitnessValueTerminator;
-import eva2.optimization.population.Population;
-import eva2.problems.AbstractProblemDouble;
-import eva2.problems.AbstractProblemDoubleOffset;
-import eva2.optimization.strategies.DifferentialEvolution;
-import eva2.optimization.strategies.InterfaceOptimizer;
-import org.apache.commons.cli.*;
-import org.reflections.Reflections;
-
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import eva2.optimization.go.InterfaceOptimizationParameters;
/**
- * Main Class for the EvA2 Command Line Interface
- *
- * The command line interface features a limited subset of the EvA2
- * optimization suite since it's difficult to parameterize all available
- * classes in EvA2 from the command line.
- * Supported Features:
- * - Select all optimization problems that implement InterfaceOptimizationProblem
- * - Select all optimizers that implement InterfaceOptimizer
- * * Not all optimizers are configurable on the command line and will run
- * with default parameters.
- * * Optimizers can use the @Description / @Parameter annotations to specify
- * parameters for CLI
- * - Configure default parameters
- * * Population size
- * * Number of optimization runs (multi-runs)
- * - Termination:
- * * Not configurable!
- * * Default: EvaluationTerminator(20000)
+ * Created by becker on 01.11.2014.
*/
-public class Main implements OptimizationStateListener, InterfacePopulationChangedEventListener {
- private static Logger LOGGER = Logger.getLogger(Main.class.getName());
- private int populationSize = 20;
- private int numberOfRuns = 1;
- private int dimension = 30;
- private long seed = System.currentTimeMillis();
-
- private AbstractProblemDoubleOffset problem;
- private InterfaceOptimizer optimizer;
- private InterfaceMutation mutator;
- private InterfaceCrossover crossover;
- private InterfaceSelection selection;
-
- private JsonObject jsonObject;
- private JsonArray optimizationRuns;
- private JsonArray generationsArray;
-
- private double[] fBias = { -4.5000000e+002, -4.5000000e+002, -4.5000000e+002, -4.5000000e+002, -3.1000000e+002,
- 3.9000000e+002, -1.8000000e+002, -1.4000000e+002, -3.3000000e+002, -3.3000000e+002, 9.0000000e+001,
- -4.6000000e+002, -1.3000000e+002, -3.0000000e+002, 1.2000000e+002, 1.2000000e+002, 1.2000000e+002,
- 1.0000000e+001, 1.0000000e+001, 1.0000000e+001, 3.6000000e+002, 3.6000000e+002, 3.6000000e+002,
- 2.6000000e+002, 2.6000000e+002};
-
- /**
- * Creates a set of default options used in all optimizations.
- *
- * @return Options Default options used for optimizations
- */
- private Options createDefaultCommandLineOptions() {
- Options opt = new Options();
-
- opt.addOption(OptionBuilder
- .withLongOpt("optimizer")
- .withDescription("Optimizer")
- .hasArg()
- .create("op")
- );
-
- opt.addOption("ps", "popsize", true, "Population size");
- opt.addOption("n", "runs", true, "Number of runs to perform");
- opt.addOption("s", "seed", true, "Random seed");
-
- // Those two only make sense when used in an algorithm with mutation/crossover
- opt.addOption("pc", true, "Crossover Probability");
- opt.addOption("pm", true, "Mutation Probability");
-
- opt.addOption("mutator", true, "Mutator Operator");
- opt.addOption("crossover", true, "Crossover Operator");
- opt.addOption("selection", true, "Selection Operator");
-
- opt.addOption(OptionBuilder
- .withLongOpt("help")
- .withDescription("Shows this help message or specific help for [optimizer]")
- .hasOptionalArgs(1)
- .create('h')
- );
-
- opt.addOption(OptionBuilder
- .withLongOpt("problem")
- .withDescription("Select Optimization Problem to optimize.")
- .hasArg()
- .create('p')
- );
- opt.addOption("dim", true, "Problem Dimension");
- return opt;
- }
-
-
-
- @Override
- public void performedStop() {
- LOGGER.info("Optimization stopped.");
- }
-
- @Override
- public void performedStart(String infoString) {
- LOGGER.info("Optimization started.");
- }
-
- @Override
- public void performedRestart(String infoString) {
- LOGGER.info("Optimization restarted.");
- }
-
- @Override
- public void updateProgress(int percent, String msg) {
- printProgressBar(percent);
- }
-
- public static void printProgressBar(int percent) {
- StringBuilder bar = new StringBuilder("[");
-
- for (int i = 0; i < 50; i++) {
- if (i < (percent / 2)) {
- bar.append("=");
- } else if (i == (percent / 2)) {
- bar.append(">");
- } else {
- bar.append(" ");
- }
- }
-
- bar.append("] " + percent + "% ");
- System.out.print("\r" + bar.toString());
- }
-
- public static Map> createOptimizerList() {
- Map> optimizerList = new TreeMap<>();
-
- Reflections reflections = new Reflections("eva2.optimization.strategies");
- Set> optimizers = reflections.getSubTypesOf(InterfaceOptimizer.class);
- for (Class extends InterfaceOptimizer> optimizer : optimizers) {
- // We only want instantiable classes
- if (optimizer.isInterface() || Modifier.isAbstract(optimizer.getModifiers())) {
- continue;
- }
- optimizerList.put(optimizer.getSimpleName(), optimizer);
- }
- return optimizerList;
- }
-
- public static Map> createProblemList() {
- Map> problemList = new TreeMap<>();
- Reflections reflections = new Reflections("eva2.problems");
- Set> problems = reflections.getSubTypesOf(AbstractProblemDoubleOffset.class);
- for (Class extends AbstractProblemDoubleOffset> problem : problems) {
- // We only want instantiable classes
- if (problem.isInterface() || Modifier.isAbstract(problem.getModifiers())) {
- continue;
- }
- problemList.put(problem.getSimpleName(), problem);
- }
- return problemList;
- }
-
- public static Map> createMutatorList() {
- Map> mutationList = new TreeMap<>();
- Reflections reflections = new Reflections("eva2.optimization.operator.mutation");
- Set> mutators = reflections.getSubTypesOf(InterfaceMutation.class);
- for (Class extends InterfaceMutation> mutator : mutators) {
- // We only want instantiable classes
- if (mutator.isInterface() || Modifier.isAbstract(mutator.getModifiers())) {
- continue;
- }
- mutationList.put(mutator.getSimpleName(), mutator);
- }
- return mutationList;
- }
-
- public static Map> createCrossoverList() {
- Map> crossoverList = new TreeMap<>();
- Reflections reflections = new Reflections("eva2.optimization.operator.crossover");
- Set> crossovers = reflections.getSubTypesOf(InterfaceCrossover.class);
- for (Class extends InterfaceCrossover> crossover : crossovers) {
- // We only want instantiable classes
- if (crossover.isInterface() || Modifier.isAbstract(crossover.getModifiers())) {
- continue;
- }
- crossoverList.put(crossover.getSimpleName(), crossover);
- }
- return crossoverList;
- }
-
- public static Map> createSelectionList() {
- Map> selectionList = new TreeMap<>();
- Reflections reflections = new Reflections("eva2.optimization.operator.selection");
- Set> selections = reflections.getSubTypesOf(InterfaceSelection.class);
- for (Class extends InterfaceSelection> selection : selections) {
- // We only want instantiable classes
- if (selection.isInterface() || Modifier.isAbstract(selection.getModifiers())) {
- continue;
- }
- selectionList.put(selection.getSimpleName(), selection);
- }
- return selectionList;
- }
-
-
-
- public static void showHelp(Options options) {
- HelpFormatter helpFormatter = new HelpFormatter();
- helpFormatter.printHelp("java -jar EvA2.jar", "Global Parameters", options, "", true);
- }
+public class Main {
public static void main(String[] args) {
- Main optimizationMain = new Main(args);
- optimizationMain.runOptimization();
- }
+ InterfaceOptimizationParameters parameters = OptimizationBuilder.parseArguments(args);
- public Main(String[] args) {
- int index = Arrays.asList(args).indexOf("--");
- String[] programParams = args;
- String[] optimizerParams;
-
- if (index >= 0) {
- programParams = Arrays.copyOfRange(args, 0, index);
- optimizerParams = Arrays.copyOfRange(args, index + 1, args.length);
- } else {
- optimizerParams = new String[]{};
- }
-
- this.jsonObject = new JsonObject();
- this.optimizationRuns = new JsonArray();
- this.generationsArray = new JsonArray();
-
- /**
- * Default command line options only require help or optimizer.
- * Later we build extended command line options depending on
- * the selected optimizer.
- */
- Options defaultOptions = this.createDefaultCommandLineOptions();
-
- /**
- * Parse default options.
- */
- CommandLineParser cliParser = new BasicParser();
- CommandLine commandLine = null;
- try {
- commandLine = cliParser.parse(defaultOptions, programParams);
- } catch (ParseException e) {
- showHelp(defaultOptions);
- System.exit(-1);
- }
-
- /**
- * Process help and help sub pages.
- */
- if (commandLine.hasOption("help")) {
- String helpOption = commandLine.getOptionValue("help");
- if (helpOption == null) {
- showHelp(defaultOptions);
- } else {
- switch (helpOption) {
- case "optimizer":
- showOptimizerHelp();
- break;
- case "problem":
- listProblems();
- break;
- default:
- showHelp(defaultOptions);
- break;
- }
- }
-
- System.exit(0);
- }
-
- // OK, so we've got valid parameters - let's setup the optimizer and problem
- if (commandLine.hasOption("popsize")) {
- this.populationSize = Integer.parseInt(commandLine.getOptionValue("popsize"));
- }
-
- if (commandLine.hasOption("runs")) {
- this.numberOfRuns = Integer.parseInt(commandLine.getOptionValue("runs"));
- }
-
- if (commandLine.hasOption("seed")) {
- this.seed = Long.parseLong(commandLine.getOptionValue("seed"));
- }
-
- if (commandLine.hasOption("dim")) {
- this.dimension = Integer.parseInt(commandLine.getOptionValue("dim"));
- }
-
- if (commandLine.hasOption("problem")) {
- String problemName = commandLine.getOptionValue("problem");
- setProblemFromName(problemName);
- this.problem.setProblemDimension(this.dimension);
- } else {
- LOGGER.severe("No problem specified. Please specify a problem with '--problem'.");
- System.exit(-1);
- }
-
-
- if (commandLine.hasOption("mutator")) {
- String mutatorName = commandLine.getOptionValue("mutator");
- try {
- setMutatorFromName(mutatorName);
- } catch (Exception ex) {
- System.out.println(ex.getMessage());
- System.exit(-1);
- }
- } else {
- this.mutator = new MutateDefault();
- }
-
- if (commandLine.hasOption("crossover")) {
- String crossoverName = commandLine.getOptionValue("crossover");
- try {
- setCrossoverFromName(crossoverName);
- } catch (Exception ex) {
- System.out.println(ex.getMessage());
- System.exit(-1);
- }
- } else {
- this.crossover = new CrossoverESDefault();
- }
-
- if (commandLine.hasOption("selection")) {
- String selectionName = commandLine.getOptionValue("selection");
- try {
- setSelectionFromName(selectionName);
- } catch (Exception ex) {
- System.out.println(ex.getMessage());
- System.exit(-1);
- }
- } else {
- this.selection = new SelectXProbRouletteWheel();
- }
-
- // Depends on mutator/crossover/selection being set
- if (commandLine.hasOption("optimizer")) {
- String optimizerName = commandLine.getOptionValue("optimizer");
- try {
- createOptimizerFromName(optimizerName, optimizerParams);
- } catch(Exception ex) {
- System.out.println(ex.getMessage());
- System.exit(-1);
- }
- }
-
- this.jsonObject.addProperty("population_size", this.populationSize);
- this.jsonObject.addProperty("number_of_runs", this.numberOfRuns);
- this.jsonObject.addProperty("dimension", this.dimension);
- this.jsonObject.addProperty("seed", this.seed);
-
- JsonObject problemObject = new JsonObject();
- problemObject.addProperty("name", this.problem.getName());
- problemObject.addProperty("dimension", 30);
- this.jsonObject.add("problem", problemObject);
- }
-
- private void setMutatorFromName(String mutatorName) {
- Map> mutatorList = createMutatorList();
-
- Class extends InterfaceMutation> mutator = mutatorList.get(mutatorName);
- try {
- this.mutator = mutator.newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
-
- private void setCrossoverFromName(String crossoverName) {
- Map> crossoverList = createCrossoverList();
-
- Class extends InterfaceCrossover> crossover = crossoverList.get(crossoverName);
- try {
- this.crossover = crossover.newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
-
- private void setSelectionFromName(String selectionName) {
- Map> selectionList = createSelectionList();
-
- Class extends InterfaceSelection> selection = selectionList.get(selectionName);
- try {
- this.selection = selection.newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * This method will create the various optimizers that are supported on the CLI.
- * It's a really messy process since neither Java nor args4j/apache-cli can handle
- * complex object parameters. The trick here is that all parameters after the
- * double-dash (--) are treated as parameters for the optimization algorithm.
- *
- * @param optimizerName The name of the optimizer.
- * @param optimizerParams The remaining command line parameters.
- * @throws Exception
- */
- private void createOptimizerFromName(String optimizerName, String[] optimizerParams) throws Exception {
- Options opt = new Options();
- CommandLineParser cliParser = new BasicParser();
- CommandLine commandLine = null;
-
- switch(optimizerName) {
- case "DifferentialEvolution": {
- opt.addOption("F", true, "Differential Weight");
- opt.addOption("CR", true, "Crossover Rate");
- opt.addOption("DEType", true, "DE Type ()");
- /**
- * Parse default options.
- */
- try {
- commandLine = cliParser.parse(opt, optimizerParams);
- } catch (ParseException e) {
- showHelp(opt);
- System.exit(-1);
- }
-
-
- double f = 0.8, lambda = 0.6, cr = 0.6;
- if (commandLine.hasOption("F")) {
- f = Double.parseDouble(commandLine.getOptionValue("F"));
- }
-
- if (commandLine.hasOption("CR")) {
- cr = Double.parseDouble(commandLine.getOptionValue("CR"));
- }
-
- this.optimizer = OptimizerFactory.createDifferentialEvolution(this.problem, this.populationSize, f, lambda, cr, this);
-
- if (commandLine.hasOption("DEType")) {
- ((DifferentialEvolution)this.optimizer).setDEType(
- DEType.getFromId(
- Integer.parseInt(commandLine.getOptionValue("DEType"))
- )
- );
- }
-
- break;
- }
- case "GeneticAlgorithm": {
- double pm = 0.01, pc = 0.5;
- opt.addOption("pm", true, "Mutation Probability");
- opt.addOption("pc", true, "Crossover Probability");
-
- /**
- * Parse default options.
- */
- try {
- commandLine = cliParser.parse(opt, optimizerParams);
- } catch (ParseException e) {
- showHelp(opt);
- System.exit(-1);
- }
-
- if (commandLine.hasOption("pm")) {
- pm = Double.parseDouble(commandLine.getOptionValue("pm"));
- }
-
- if (commandLine.hasOption("pc")) {
- pc = Double.parseDouble(commandLine.getOptionValue("pc"));
- }
-
- this.optimizer = OptimizerFactory.createGeneticAlgorithm(mutator, pm, crossover, pc, selection, this.populationSize, this.problem, this);
- break;
- }
- case "ParticleSwarmOptimization": {
- double phi1 = 2.05, phi2 = 2.05, speedLimit = 0.1;
- int topoRange = 2;
- PSOTopology selectedTopology = PSOTopology.star;
-
- opt.addOption("speedLimit", true, "Speed Limit");
- opt.addOption("topology", true, "Particle Swarm Topology (0-7)");
- opt.addOption("phi1", true, "Phi 1");
- opt.addOption("phi2", true, "Phi 2");
-
- /**
- * Parse default options.
- */
- try {
- commandLine = cliParser.parse(opt, optimizerParams);
- } catch (ParseException e) {
- showHelp(opt);
- System.exit(-1);
- }
-
- if (commandLine.hasOption("phi1")) {
- phi1 = Double.parseDouble(commandLine.getOptionValue("phi1"));
- }
-
- if (commandLine.hasOption("phi2")) {
- phi2 = Double.parseDouble(commandLine.getOptionValue("phi2"));
- }
-
- if (commandLine.hasOption("topology")) {
- selectedTopology = PSOTopology.getFromId(Integer.parseInt(commandLine.getOptionValue("topology")));
- }
-
- if (commandLine.hasOption("speedLimit")) {
- speedLimit = Double.parseDouble(commandLine.getOptionValue("speedLimit"));
- }
-
- this.optimizer = OptimizerFactory.createParticleSwarmOptimization(problem, this.populationSize, phi1, phi2, speedLimit, selectedTopology, topoRange, this);
- break;
- }
- case "EvolutionStrategies": {
- double pm, pc;
- int mu = 5, lambda = 20;
- boolean plusStrategy = false;
-
- opt.addOption("pm", true, "Mutation Probability");
- opt.addOption("pc", true, "Crossover Probability");
- opt.addOption("mu", true, "Mu");
- opt.addOption("lambda", true, "Lambda");
- opt.addOption("plusStrategy", true, "Whether to use the plus or comma strategy.");
-
- /**
- * Parse default options.
- */
- try {
- commandLine = cliParser.parse(opt, optimizerParams);
- } catch (ParseException e) {
- showHelp(opt);
- System.exit(-1);
- }
-
- if (commandLine.hasOption("pm")) {
- pm = Double.parseDouble(commandLine.getOptionValue("pm"));
- } else {
- pm = 0.01;
- }
-
- if (commandLine.hasOption("pc")) {
- pc = Double.parseDouble(commandLine.getOptionValue("pc"));
- } else {
- pc = 0.9;
- }
-
- if (commandLine.hasOption("mu")) {
- mu = Integer.parseInt(commandLine.getOptionValue("mu"));
- }
-
- if (commandLine.hasOption("lambda")) {
- lambda = Integer.parseInt(commandLine.getOptionValue("lambda"));
- }
-
- if (commandLine.hasOption("plusStrategy")) {
- plusStrategy = Boolean.parseBoolean(commandLine.getOptionValue("plusStrategy"));
- }
-
- this.optimizer = OptimizerFactory.createEvolutionStrategy(mu, lambda, plusStrategy, this.mutator, pm, this.crossover, pc, this.selection, problem, this);
- break;
- }
- default:
- throw new Exception("Unsupported Optimizer");
- }
- }
-
- private void setProblemFromName(String problemName) {
- Map> problemList = createProblemList();
-
- Class extends AbstractProblemDoubleOffset> problem = problemList.get(problemName);
- try {
- this.problem = problem.newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
-
- //setCECDefaults(this.problem);
- }
-
- private void setCECDefaults(AbstractProblemDouble problem) {
- switch(problem.getName()) {
- case "F1-Problem": // F1: Shifted Sphere
- this.problem.setDefaultRange(100);
- this.problem.setYOffset(fBias[0]);
- break;
- case "F2-Problem": // F6: Shifted Rosenbrock's Function
- this.problem.setDefaultRange(100);
- this.problem.setYOffset(fBias[5]);
- break;
- case "F5-Problem": // F2: Schwefel's 1.2
- this.problem.setDefaultRange(100);
- this.problem.setYOffset(fBias[1]);
- break;
- case "F6-Problem": // F9: Shifted Rastrigin's Function
- this.problem.setDefaultRange(5);
- this.problem.setYOffset(fBias[8]);
- break;
- default:
- LOGGER.info("No CEC'05 default parameters for this problem found.");
- break;
- }
- }
-
- /**
- * Executes the optimization and outputs a JSON document to the command line
- * with the statistics of the optimization run(s).
- */
- private void runOptimization() {
- for(int i = 0; i < this.numberOfRuns; i++) {
- // Terminate after 10000 function evaluations OR after reaching a fitness < 0.1
- OptimizerFactory.setEvaluationTerminator(500000);
- //OptimizerFactory.setTerminator(new FitnessValueTerminator(new double[]{0.0001}));
- OptimizerFactory.addTerminator(new FitnessValueTerminator(new double[]{0.0001}), CombinedTerminator.OR);
-
- LOGGER.log(Level.INFO, "Running {0}", optimizer.getName());
-
- OptimizationParameters params = OptimizerFactory.makeParams(optimizer, this.populationSize, this.problem, this.seed, OptimizerFactory.getTerminator());
- double[] result = OptimizerFactory.optimizeToDouble(params);
-
- JsonObject optimizationDetails = new JsonObject();
- optimizationDetails.addProperty("total_time", 1.0);
- optimizationDetails.addProperty("total_function_calls", optimizer.getPopulation().getFunctionCalls());
- optimizationDetails.addProperty("termination_criteria", OptimizerFactory.terminatedBecause());
- optimizationDetails.add("generations", this.generationsArray);
-
- JsonArray solutionArray = new JsonArray();
- for(double val : result) {
- solutionArray.add(new JsonPrimitive(val));
- }
- optimizationDetails.add("solution", solutionArray);
-
- this.optimizationRuns.add(optimizationDetails);
-
- // Needs to be re-created here.
- this.generationsArray = new JsonArray();
- }
-
- this.jsonObject.add("runs", this.optimizationRuns);
-
- Gson gson = new GsonBuilder().setPrettyPrinting().create();
- System.out.println(gson.toJson(this.jsonObject));
- }
-
- private static void showOptimizerHelp() {
- Map> optimizerList = createOptimizerList();
-
- System.out.println("Available Optimizers:");
- for (String name : optimizerList.keySet()) {
- System.out.printf("%s\n", name);
- }
- }
-
- private static void listProblems() {
- Map> problemList = createProblemList();
-
- System.out.println("Available Problems:");
- for (String name : problemList.keySet()) {
- System.out.printf("%s\n", name);
- }
- }
-
- @Override
- public void registerPopulationStateChanged(Object source, String name) {
- if (name.equals("NextGenerationPerformed")) {
- InterfaceOptimizer optimizer = (InterfaceOptimizer)source;
- Population population = optimizer.getPopulation();
-
- JsonObject newGeneration = new JsonObject();
- newGeneration.addProperty("generation", population.getGeneration());
- newGeneration.addProperty("function_calls", population.getFunctionCalls());
-
- JsonArray bestFitness = new JsonArray();
- for(double val : population.getBestFitness()) {
- bestFitness.add(new JsonPrimitive(val));
- }
- newGeneration.add("best_fitness", bestFitness);
-
- JsonArray meanFitness = new JsonArray();
- for(double val : population.getMeanFitness()) {
- meanFitness.add(new JsonPrimitive(val));
- }
- newGeneration.add("mean_fitness", meanFitness);
- //System.out.println(newGeneration.toString());
- this.generationsArray.add(newGeneration);
- }
}
}
diff --git a/src/eva2/cli/OptimizationBuilder.java b/src/eva2/cli/OptimizationBuilder.java
new file mode 100644
index 00000000..9cf317d1
--- /dev/null
+++ b/src/eva2/cli/OptimizationBuilder.java
@@ -0,0 +1,208 @@
+package eva2.cli;
+
+import eva2.gui.BeanInspector;
+import eva2.optimization.go.InterfaceOptimizationParameters;
+import eva2.optimization.modules.OptimizationParameters;
+import eva2.tools.ReflectPackage;
+import eva2.util.annotation.Hidden;
+import eva2.util.annotation.Parameter;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+
+class ArgumentTree extends LinkedHashMap {
+ private Object value;
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public Object getValue() {
+ return this.value;
+ }
+
+ @Override
+ public String toString() {
+ return ((value != null) ? value.toString() + ", " : "") + super.toString();
+ }
+
+ /**
+ * If there are no key, value pairs present and the value is unset,
+ * this tree belongs to a flag.
+ *
+ * @return
+ */
+ public boolean isFlag() {
+ return this.size() == 0 && this.value == null;
+ }
+}
+/**
+ *
+ */
+public final class OptimizationBuilder {
+ private OptimizationBuilder() {}
+
+ public static InterfaceOptimizationParameters parseArguments(String[] args) {
+ HashMap argumentMap = new HashMap<>(args.length/2);
+ int i = 0;
+ while (i < args.length) {
+ // Is it a parameter?
+ if (args[i].startsWith("--")) {
+ String key = args[i].substring(2);
+ String value = null;
+ // Is the next a value?
+ if (i < args.length - 1 && !args[i+1].startsWith("--")) {
+ value = args[i + 1];
+ argumentMap.put(key, value);
+ i = i + 2;
+ } else {
+ argumentMap.put(key, null);
+ i++;
+ }
+ }
+ }
+ System.out.println(argumentMap.toString());
+ ArgumentTree argumentTree = new ArgumentTree();
+ for (String key : argumentMap.keySet()) {
+ insertIntoArgumentTree(argumentTree, key, argumentMap.get(key));
+ }
+ System.out.println(argumentTree.toString());
+
+ return constructFromArgumentTree(OptimizationParameters.class, argumentTree);
+ }
+
+ private static void insertIntoArgumentTree(ArgumentTree tree, String key, String value) {
+ // Basic type?
+ if (!key.contains("-")) {
+ if (!tree.containsKey(key)) {
+ tree.put(key, new ArgumentTree());
+ }
+ ((ArgumentTree)tree.get(key)).setValue(value);
+ } else {
+ String baseKey = key.substring(0, key.indexOf('-'));
+ String restKey = key.substring(key.indexOf('-') + 1);
+ if (!tree.containsKey(baseKey)) {
+ tree.put(baseKey, new ArgumentTree());
+ }
+ insertIntoArgumentTree((ArgumentTree)tree.get(baseKey), restKey, value);
+ }
+ }
+
+ /**
+ *
+ * @param clazz
+ * @param tree Tree containing key, value pairs
+ */
+ private static T constructFromArgumentTree(Class clazz, ArgumentTree tree) {
+ T instance = null;
+
+ // Create new instance
+ if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
+ // Find subclasses of clazz that match tree.getValue()
+ } else {
+ Class>[] params = new Class[0];
+ try {
+ Constructor constructor = clazz.getConstructor(params);
+ instance = (T)constructor.newInstance(new Object[]{});
+ } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ /* No need to continue if there are no parameters to set */
+ if (tree.isEmpty()) {
+ return instance;
+ }
+
+ BeanInfo info;
+ try {
+ if (clazz.isInterface()) {
+ info = Introspector.getBeanInfo(clazz);
+ } else {
+ info = Introspector.getBeanInfo(clazz, Object.class);
+ }
+ PropertyDescriptor[] properties = info.getPropertyDescriptors();
+ int foundParameters = 0;
+ for (PropertyDescriptor pd : properties) {
+ String name = pd.getName();
+ Method getter = pd.getReadMethod();
+ Method setter = pd.getWriteMethod();
+ Class> type = pd.getPropertyType();
+ // We skip non-existing setters or setters that are hidden by annotation
+ if (setter == null || setter.isAnnotationPresent(Hidden.class)) {
+ continue;
+ }
+ System.out.println(name + " = " + " type = " + type);
+
+ // We use the name of the descriptor or if possible
+ // one that is given by the @Parameter annotation.
+ if (setter.isAnnotationPresent(Parameter.class)) {
+ Parameter param = setter.getAnnotation(Parameter.class);
+ if (!param.name().isEmpty()) {
+ name = param.name();
+ }
+ }
+
+ /**
+ * If the tree contains this property we try to set it on the object.
+ */
+ if (tree.containsKey(name)) {
+ foundParameters++;
+ Object obj;
+ if (type.isPrimitive() && ((ArgumentTree)tree.get(name)).getValue() != null) {
+ obj = BeanInspector.stringToPrimitive((String)((ArgumentTree) tree.get(name)).getValue(), type);
+ } else {
+ // The subtree has the name of the class
+ String className = (String)((ArgumentTree)tree.get(name)).getValue();
+
+ Class subType;
+ if (className != null) {
+ // Try to get the actual class from its name
+ subType = getClassFromName(className, type);
+ } else {
+ subType = type;
+ }
+
+ // Here the recursion starts
+ obj = constructFromArgumentTree(subType, (ArgumentTree) tree.get(name));
+ }
+
+ // We preserve the default if obj is null
+ if (obj != null) {
+ BeanInspector.callIfAvailable(instance, setter.getName(), new Object[]{obj});
+ }
+ }
+
+ // If we configured all parameters in the tree we can break the loop
+ if (tree.size() == foundParameters) {
+ break;
+ }
+ }
+ } catch (IntrospectionException ex) {
+ ex.printStackTrace();
+ }
+
+ return instance;
+ }
+
+ private static Class> getClassFromName(String name, Class type) {
+ Class>[] classes = ReflectPackage.getAssignableClassesInPackage("eva2", type, true, true);
+ for (Class clazz : classes) {
+ // We allow both the fully qualified name (eva2.optimization.strategies.GeneticAlgorithm
+ // and the simple name (GeneticAlgorithm)
+ if (clazz.getName().equals(name) || clazz.getSimpleName().equals(name)) {
+ return clazz;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/eva2/optimization/individuals/ESIndividualDoubleData.java b/src/eva2/optimization/individuals/ESIndividualDoubleData.java
index 854995f6..c1d7aa3e 100644
--- a/src/eva2/optimization/individuals/ESIndividualDoubleData.java
+++ b/src/eva2/optimization/individuals/ESIndividualDoubleData.java
@@ -105,9 +105,6 @@ public class ESIndividualDoubleData extends AbstractEAIndividual implements Inte
}
}
-/************************************************************************************
- * InterfaceDataTypeDouble methods
- */
/**
* This method allows you to request a certain amount of double data
*
@@ -235,9 +232,6 @@ public class ESIndividualDoubleData extends AbstractEAIndividual implements Inte
System.arraycopy(doubleData, 0, this.genotype, 0, doubleData.length);
}
-/************************************************************************************
- * AbstractEAIndividual methods
- */
/**
* This method will allow a default initialisation of the individual
*
@@ -304,9 +298,6 @@ public class ESIndividualDoubleData extends AbstractEAIndividual implements Inte
return strB.toString();
}
-/************************************************************************************
- * InterfaceESIndividual methods
- */
/**
* This method will allow the user to read the ES 'genotype'
*
diff --git a/src/eva2/optimization/individuals/GAIndividualDoubleData.java b/src/eva2/optimization/individuals/GAIndividualDoubleData.java
index 21770a5d..20682a31 100644
--- a/src/eva2/optimization/individuals/GAIndividualDoubleData.java
+++ b/src/eva2/optimization/individuals/GAIndividualDoubleData.java
@@ -10,6 +10,7 @@ import eva2.optimization.operator.mutation.MutateGAUniform;
import eva2.problems.InterfaceOptimizationProblem;
import eva2.tools.math.RNG;
import eva2.util.annotation.Description;
+import eva2.util.annotation.Parameter;
import java.util.BitSet;
@@ -229,10 +230,6 @@ public class GAIndividualDoubleData extends AbstractEAIndividual implements Inte
}
}
-/************************************************************************************
- * AbstractEAIndividual methods
- */
-
/**
* This method will initialize the individual with a given value for the
* phenotype.
@@ -373,6 +370,7 @@ public class GAIndividualDoubleData extends AbstractEAIndividual implements Inte
*
* @param coding The used genotype coding method
*/
+ @Parameter(name = "coding", description = "Choose the coding to use.")
public void setGACoding(InterfaceGADoubleCoding coding) {
this.doubleCoding = coding;
}
@@ -381,16 +379,13 @@ public class GAIndividualDoubleData extends AbstractEAIndividual implements Inte
return this.doubleCoding;
}
- public String gADoubleCodingTipText() {
- return "Choose the coding to use.";
- }
-
/**
* This method allows you to set the number of mulitruns that are to be performed,
* necessary for stochastic optimizers to ensure reliable results.
*
* @param precision The number of multiruns that are to be performed
*/
+ @Parameter(description = "Gives the number of bits to be used to code a double.")
public void setPrecision(int precision) {
this.precision = precision;
}
@@ -398,8 +393,4 @@ public class GAIndividualDoubleData extends AbstractEAIndividual implements Inte
public int getPrecision() {
return this.precision;
}
-
- public String precisionTipText() {
- return "Gives the number of bits to be used to code a double.";
- }
}
diff --git a/src/eva2/optimization/population/Population.java b/src/eva2/optimization/population/Population.java
index 32f537ec..97462e20 100644
--- a/src/eva2/optimization/population/Population.java
+++ b/src/eva2/optimization/population/Population.java
@@ -15,6 +15,7 @@ import eva2.tools.math.Mathematics;
import eva2.tools.math.RNG;
import eva2.tools.math.StatisticUtils;
import eva2.util.annotation.Description;
+import eva2.util.annotation.Hidden;
import eva2.util.annotation.Parameter;
import java.util.*;
@@ -602,6 +603,7 @@ public class Population extends ArrayList implements PopulationInterface, Clonea
return historyList;
}
+ @Hidden
public void setHistory(LinkedList theHist) {
historyList = theHist;
}
@@ -684,6 +686,7 @@ public class Population extends ArrayList implements PopulationInterface, Clonea
*
* @param d The new number of functioncalls.
*/
+ @Hidden
public void setFunctionCalls(int d) {
this.functionCallCount = d;
}
@@ -738,6 +741,7 @@ public class Population extends ArrayList implements PopulationInterface, Clonea
*
* @param gen the value to set as new generation index
*/
+ @Hidden
public void setGeneration(int gen) {
this.generationCount = gen;
}
@@ -2519,11 +2523,8 @@ public class Population extends ArrayList implements PopulationInterface, Clonea
return seedCardinality;
}
+ @Parameter(description = "The initial cardinality for binary genotype individuals, given as pair of mean and std.dev.")
public void setSeedCardinality(Pair seedCardinality) {
this.seedCardinality = seedCardinality;
}
-
- public String seedCardinalityTipText() {
- return "The initial cardinality for binary genotype individuals, given as pair of mean and std.dev.";
- }
}
diff --git a/src/eva2/optimization/statistics/EvAStatisticalEvaluation.java b/src/eva2/optimization/statistics/EvAStatisticalEvaluation.java
index 5e6d9fbb..7db8162f 100644
--- a/src/eva2/optimization/statistics/EvAStatisticalEvaluation.java
+++ b/src/eva2/optimization/statistics/EvAStatisticalEvaluation.java
@@ -6,11 +6,12 @@ import eva2.optimization.enums.StatisticsOnTwoSampledData;
import eva2.tools.ReflectPackage;
import eva2.tools.StringTools;
import eva2.tools.math.Mathematics;
-import org.apache.commons.math3.stat.ranking.NaNStrategy;
-import org.apache.commons.math3.stat.ranking.TiesStrategy;
import java.text.DecimalFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
import java.util.logging.Logger;
/**
@@ -257,19 +258,15 @@ public class EvAStatisticalEvaluation {
private static String calculateMannWhitney(String field, OptimizationJob job1, OptimizationJob job2) {
double[] dat1 = job1.getDoubleDataColumn(field);
double[] dat2 = job2.getDoubleDataColumn(field);
- org.apache.commons.math3.stat.inference.MannWhitneyUTest mU = new org.apache.commons.math3.stat.inference.MannWhitneyUTest(NaNStrategy.FAILED, TiesStrategy.AVERAGE);
double t = Double.NaN;
if (dat1 != null && dat2 != null) {
-
- return "" + mU.mannWhitneyUTest(dat1, dat2);
- /*
Object obj = ReflectPackage.instantiateWithParams("jsc.independentsamples.MannWhitneyTest", new Object[]{dat1, dat2}, null);
if (obj != null) {
Object sp = BeanInspector.callIfAvailable(obj, "getSP", new Object[]{});
t = (Double) sp;
} else {
LOGGER.warning("For the MannWhitney test, the JSC package is required on the class path!");
- }*/
+ }
}
return "" + t;
}
diff --git a/src/eva2/optimization/strategies/MultiObjectiveCMAES.java b/src/eva2/optimization/strategies/MultiObjectiveCMAES.java
index b5ab0ad2..38a42de8 100644
--- a/src/eva2/optimization/strategies/MultiObjectiveCMAES.java
+++ b/src/eva2/optimization/strategies/MultiObjectiveCMAES.java
@@ -100,7 +100,7 @@ public class MultiObjectiveCMAES extends AbstractOptimizer implements Serializab
/*
* (non-Javadoc)
*
- * @see eva2.optimization.strategies.InterfaceOptimizer#init()
+ * @see eva2.optimization.strategies.InterfaceOptimizer#initialize()
*/
@Override
public void initialize() {
diff --git a/src/eva2/problems/AbstractOptimizationProblem.java b/src/eva2/problems/AbstractOptimizationProblem.java
index 17943a1f..bf1052d6 100644
--- a/src/eva2/problems/AbstractOptimizationProblem.java
+++ b/src/eva2/problems/AbstractOptimizationProblem.java
@@ -87,13 +87,11 @@ public abstract class AbstractOptimizationProblem implements InterfaceOptimizati
return parallelThreads;
}
+ @Parameter(name = "parallel", description = "Set the number of threaded parallel function evaluations - interesting for slow functions and generational optimizers.")
public void setParallelThreads(int parallelThreads) {
this.parallelThreads = parallelThreads;
}
- public String parallelThreadsTipText() {
- return "Set the number of threaded parallel function evaluations - interesting for slow functions and generational optimizers.";
- }
/**
* This method initializes the problem instance.
@@ -406,10 +404,6 @@ public abstract class AbstractOptimizationProblem implements InterfaceOptimizati
return template;
}
- public String individualTemplateTipText() {
- return "Choose the individual representation to use.";
- }
-
/**
* This method extracts the individuals from a given population that are assumed to correspond to local or global optima.
* Similar individuals are clustered together with a density based clustering method
diff --git a/src/eva2/problems/AbstractProblemDouble.java b/src/eva2/problems/AbstractProblemDouble.java
index 74cf3d59..6bca47d6 100644
--- a/src/eva2/problems/AbstractProblemDouble.java
+++ b/src/eva2/problems/AbstractProblemDouble.java
@@ -22,6 +22,7 @@ import eva2.tools.diagram.ColorBarCalculator;
import eva2.tools.math.Jama.Matrix;
import eva2.tools.math.Mathematics;
import eva2.tools.math.RNG;
+import eva2.util.annotation.Parameter;
/**
* For a double valued problem, there are two main methods to implement:
@@ -285,6 +286,7 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem
*
* @param noise The sigma for a gaussian random number.
*/
+ @Parameter(description = "Gaussian noise level on the fitness value.")
public void setNoise(double noise) {
if (noise < 0) {
noise = 0;
@@ -301,15 +303,12 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem
return this.noise;
}
- public String noiseTipText() {
- return "Gaussian noise level on the fitness value.";
- }
-
/**
* This method allows you to choose the EA individual used by the problem.
*
* @param indy The EAIndividual type
*/
+ @Parameter(name = "individual", description = "Base individual type defining the data representation and mutation/crossover operators")
public void setEAIndividual(InterfaceDataTypeDouble indy) {
this.template = (AbstractEAIndividual) indy;
}
@@ -324,10 +323,6 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem
return (InterfaceDataTypeDouble) this.template;
}
- public String EAIndividualTipText() {
- return "Set the base individual type defining the data representation and mutation/crossover operators";
- }
-
/**
* A (symmetric) absolute range limit.
*
@@ -351,6 +346,7 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem
return "Absolute limit for the symmetric range in any dimension";
}
+ @Parameter(name = "rotate", description = "If marked, the function is rotated by 22.5 degrees along every axis.")
public void setDoRotation(boolean doRotation) {
this.doRotation = doRotation;
if (!doRotation) {
@@ -362,10 +358,6 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem
return doRotation;
}
- public String doRotationTipText() {
- return "If marked, the function is rotated by 22.5 degrees along every axis.";
- }
-
/**
* *******************************************************************************************************************
* These are for InterfaceParamControllable
diff --git a/src/eva2/problems/SimpleProblemWrapper.java b/src/eva2/problems/SimpleProblemWrapper.java
index dc0623ab..494f65d9 100644
--- a/src/eva2/problems/SimpleProblemWrapper.java
+++ b/src/eva2/problems/SimpleProblemWrapper.java
@@ -12,6 +12,7 @@ import eva2.problems.simple.InterfaceSimpleProblem;
import eva2.problems.simple.SimpleF1;
import eva2.problems.simple.SimpleProblemBinary;
import eva2.problems.simple.SimpleProblemDouble;
+import eva2.util.annotation.Parameter;
import java.util.BitSet;
@@ -164,6 +165,7 @@ public class SimpleProblemWrapper extends AbstractOptimizationProblem {
/**
* @param simProb the simProb to set
*/
+ @Parameter(description = "Set the simple problem class which is to be optimized")
public void setSimpleProblem(InterfaceSimpleProblem> simProb) {
this.simProb = simProb;
initTemplate();
@@ -186,19 +188,13 @@ public class SimpleProblemWrapper extends AbstractOptimizationProblem {
}
}
- /**
- *
- */
- public String simpleProblemTipText() {
- return "Set the simple problem class which is to be optimized";
- }
-
/**
* This method allows you to choose how much noise is to be added to the
* fitness. This can be used to make the optimization problem more difficult.
*
* @param noise The sigma for a gaussian random number.
*/
+ @Parameter(description = "Gaussian noise level on the fitness value.")
public void setNoise(double noise) {
if (noise < 0) {
noise = 0;
@@ -210,11 +206,6 @@ public class SimpleProblemWrapper extends AbstractOptimizationProblem {
return this.noise;
}
- public String noiseTipText() {
- return "Gaussian noise level on the fitness value.";
- }
-
-
/**
* A (symmetric) absolute range limit.
*
@@ -229,15 +220,12 @@ public class SimpleProblemWrapper extends AbstractOptimizationProblem {
*
* @param defaultRange
*/
+ @Parameter(name = "range", description = "Absolute limit for the symmetric range in any dimension")
public void setDefaultRange(double defaultRange) {
this.defaultRange = defaultRange;
initTemplate();
}
- public String defaultRangeTipText() {
- return "Absolute limit for the symmetric range in any dimension";
- }
-
/**
* Take care that all properties which may be hidden (and currently are) send a "hide" message to the Java Bean properties.
* This is called by PropertySheetPanel in use with the GenericObjectEditor.
@@ -246,16 +234,12 @@ public class SimpleProblemWrapper extends AbstractOptimizationProblem {
setSimpleProblem(getSimpleProblem());
}
+ @Parameter(name = "individual", description = "Set the individual properties for the optimization")
public void setIndividualTemplate(AbstractEAIndividual indy) {
resetTemplate = false;
template = indy;
}
- @Override
- public String individualTemplateTipText() {
- return "Set the individual properties for the optimization";
- }
-
/**
* This method returns a string describing the optimization problem.
*
diff --git a/src/eva2/tools/Serializer.java b/src/eva2/tools/Serializer.java
index e64e5d5b..f483a3f6 100644
--- a/src/eva2/tools/Serializer.java
+++ b/src/eva2/tools/Serializer.java
@@ -1,7 +1,5 @@
package eva2.tools;
-import com.google.gson.Gson;
-
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;