From c7969623b44f375e30fa3f15dcd7581609276a0f Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Fri, 4 Apr 2014 17:14:44 +0100 Subject: Parameter validation refactored and fully functional. --- src/jcgp/JCGP.java | 141 +++++++++++++++------ src/jcgp/backend/modules/ea/MuPlusLambda.java | 37 +++++- .../backend/modules/ea/TournamentSelection.java | 4 +- src/jcgp/backend/parameters/BooleanParameter.java | 9 +- src/jcgp/backend/parameters/DoubleParameter.java | 2 +- src/jcgp/backend/parameters/IntegerParameter.java | 2 +- src/jcgp/backend/parameters/Parameter.java | 8 +- src/jcgp/backend/parameters/ParameterStatus.java | 2 +- src/jcgp/backend/population/Chromosome.java | 1 + src/jcgp/gui/GUI.java | 126 +++++++++++------- src/jcgp/gui/console/GUIConsole.java | 7 +- src/jcgp/gui/settings/SettingsPane.java | 109 +++++++++------- .../settings/parameters/GUIBooleanParameter.java | 43 +++++-- .../settings/parameters/GUIDoubleParameter.java | 41 ++++-- .../settings/parameters/GUIIntegerParameter.java | 42 ++++-- src/jcgp/gui/settings/parameters/GUIParameter.java | 18 ++- 16 files changed, 390 insertions(+), 202 deletions(-) (limited to 'src') diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index 0c75f2b..962ddec 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -117,7 +117,7 @@ public class JCGP { private void createBaseParameters() { parameters.put("rows", new IntegerParameter(8, "Rows", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Chromosome must have at least 1 row."); @@ -128,7 +128,7 @@ public class JCGP { }); parameters.put("columns", new IntegerParameter(9, "Columns", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Chromosome must have at least 1 column."); @@ -139,7 +139,7 @@ public class JCGP { }); parameters.put("inputs", new IntegerParameter(3, "Inputs", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Chromosome must have at least 1 input."); @@ -150,7 +150,7 @@ public class JCGP { }); parameters.put("outputs", new IntegerParameter(3, "Outputs", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Chromosome must have at least 1 output."); @@ -161,7 +161,7 @@ public class JCGP { }); parameters.put("popSize", new IntegerParameter(5, "Population", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Population size must be at least 1."); @@ -172,7 +172,7 @@ public class JCGP { }); parameters.put("levelsBack", new IntegerParameter(2, "Levels back", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Levels back must be at least 1."); @@ -187,7 +187,7 @@ public class JCGP { IntegerParameter nodes = new IntegerParameter(1, "Nodes", true, false) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { // blank } }; @@ -196,12 +196,12 @@ public class JCGP { parameters.put("generations", new IntegerParameter(1000000, "Generations") { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue <= 0) { status = ParameterStatus.INVALID; status.setDetails("Number of generations must be greater than 0."); - } else if (newValue <= getInt("currentGen")) { - status = ParameterStatus.WARNING; + } else if (newValue < getInt("currentGen")) { + status = ParameterStatus.WARNING_RESET; status.setDetails("Setting generations to less than the current generation will cause the experiment to restart."); } else { status = ParameterStatus.VALID; @@ -210,16 +210,19 @@ public class JCGP { }); parameters.put("currentGen", new IntegerParameter(1, "Generation", true, false) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { // blank } }); parameters.put("runs", new IntegerParameter(5, "Runs") { @Override - protected void validate(int newValue) { - if (newValue <= getInt("currentRun")) { - status = ParameterStatus.WARNING; + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Number of runs must be greater than 0."); + } else if (newValue < getInt("currentRun")) { + status = ParameterStatus.WARNING_RESET; status.setDetails("Setting runs to less than the current run will cause the experiment to restart."); } else { status = ParameterStatus.VALID; @@ -228,27 +231,27 @@ public class JCGP { }); parameters.put("currentRun", new IntegerParameter(1, "Run", true, false) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { // blank } }); parameters.put("arity", new IntegerParameter(0, "Max arity", true, false) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { // blank } }); - parameters.put("maxFitness", new IntegerParameter(6, "Max fitness", true, true) { + parameters.put("maxFitness", new IntegerParameter(3, "Max fitness", true, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { // blank } }); IntegerParameter seed = new IntegerParameter(123, "Seed", false, true) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { status = ParameterStatus.VALID; } }; @@ -264,7 +267,7 @@ public class JCGP { parameters.put("report", new IntegerParameter(1, "Report", false, false) { @Override - protected void validate(int newValue) { + public void validate(int newValue) { if (newValue > getInt("generations")) { status = ParameterStatus.WARNING; status.setDetails("No reports will be printed."); @@ -366,7 +369,7 @@ public class JCGP { } } - private Resources resources = new Resources(); + private final Resources resources = new Resources(); /* * The following arrays contain all available modules. These collections are read by the GUI @@ -382,7 +385,7 @@ public class JCGP { // evolutionary algorithms private EvolutionaryAlgorithm[] evolutionaryAlgorithms = new EvolutionaryAlgorithm[] { - new MuPlusLambda(), + new MuPlusLambda(resources), new TournamentSelection()}; private EvolutionaryAlgorithm evolutionaryAlgorithm; @@ -396,7 +399,7 @@ public class JCGP { */ private Population population; - private boolean solutionFound = false; + private boolean finished = false; public JCGP() { @@ -409,8 +412,7 @@ public class JCGP { fitnessFunction = fitnessFunctions[0]; - resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}), - new TestCase(new Integer[]{4, 7, 4}, new Integer[]{6, 21, 2})); + resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); } @@ -495,33 +497,88 @@ public class JCGP { } public void nextGeneration() { - fitnessFunction.evaluate(population, resources); - - if (population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness() >= resources.getInt("maxFitness")) { - solutionFound = true; - resources.println("Solution found!"); - population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).printNodes(); - } else { - resources.println("Generation: " + resources.getInt("currentGen") + ", fitness: " + population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness()); - resources.set("currentGen", resources.getInt("currentGen") + 1); + if (!finished) { + fitnessFunction.evaluate(population, resources); + + report(); + + if (resources.getInt("currentGen") < resources.getInt("generations")) { + // we still have generations left to go + if (population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness() >= resources.getInt("maxFitness")) { + // solution has been found, start next run + resources.println("Solution found in generation " + resources.getInt("currentGen") + ", chromosome: " + evolutionaryAlgorithm.getFittestChromosome()); + + if (resources.getInt("currentRun") < resources.getInt("runs")) { + // there are still runs left + resources.set("currentRun", resources.getInt("currentRun") + 1); + resources.set("currentGen", 0); + + // start a new population + population = new Population(resources); + } else { + // no more generations and no more runs, we're done + finished = true; + } + } else { + resources.set("currentGen", resources.getInt("currentGen") + 1); + } + + } else { + // the run has ended, check if any more runs must be done + resources.println("Solution not found, highest fitness achieved was " + + population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness() + + " by chromosome " + evolutionaryAlgorithm.getFittestChromosome()); + + if (resources.getInt("currentRun") < resources.getInt("runs")) { + // the run has ended but there are still runs left + resources.set("currentRun", resources.getInt("currentRun") + 1); + resources.set("currentGen", 0); + + // start a new population + population = new Population(resources); + } else { + // no more generations and no more runs, we're done + finished = true; + } + } } - + evolutionaryAlgorithm.evolve(population, mutator, resources); + } - public void start() { - while (resources.getInt("currentGen") <= resources.getInt("generations")) { - nextGeneration(); - - if (solutionFound) { - break; + private void report() { + if (resources.getInt("report") > 0) { + if (resources.getInt("currentGen") % resources.getInt("report") == 0) { + resources.println("Generation: " + resources.getInt("currentGen") + ", fitness: " + population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness()); } } + + } + + public void start() { + if (!finished) { + while (resources.getInt("currentGen") <= resources.getInt("generations")) { + nextGeneration(); + if (finished) { + break; + } + } + } + } public void reset() { - solutionFound = false; + finished = false; population = new Population(resources); + resources.set("currentGen", 1); + resources.set("currentRun", 1); + resources.println("-----------------------------"); + resources.println("New experiment"); } + public boolean isFinished() { + return finished; + } + } diff --git a/src/jcgp/backend/modules/ea/MuPlusLambda.java b/src/jcgp/backend/modules/ea/MuPlusLambda.java index 22a0876..ad8c5d8 100644 --- a/src/jcgp/backend/modules/ea/MuPlusLambda.java +++ b/src/jcgp/backend/modules/ea/MuPlusLambda.java @@ -3,8 +3,10 @@ package jcgp.backend.modules.ea; import jcgp.JCGP.Resources; import jcgp.backend.modules.ModuleStatus; import jcgp.backend.modules.mutator.Mutator; +import jcgp.backend.parameters.BooleanParameter; import jcgp.backend.parameters.IntegerParameter; import jcgp.backend.parameters.Parameter; +import jcgp.backend.parameters.ParameterStatus; import jcgp.backend.population.Population; /** @@ -19,18 +21,41 @@ public class MuPlusLambda implements EvolutionaryAlgorithm { private int fittestChromosome; private IntegerParameter parents, offspring; + private BooleanParameter report; - public MuPlusLambda() { + public MuPlusLambda(final Resources resources) { parents = new IntegerParameter(1, "Parents") { @Override - protected void validate(int newValue) { - + public void validate(int newValue) { + if (newValue + offspring.get() != resources.getInt("popSize")) { + status = ParameterStatus.INVALID; + status.setDetails("Parents + offspring must equal population size."); + } else if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("EA needs at least 1 parent."); + } else { + status = ParameterStatus.VALID; + } } }; offspring = new IntegerParameter(4, "Offspring") { @Override - protected void validate(int newValue) { - + public void validate(int newValue) { + if (newValue + parents.get() != resources.getInt("popSize")) { + status = ParameterStatus.INVALID; + status.setDetails("Parents + offspring must equal population size."); + } else if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("EA needs at least 1 offspring."); + } else { + status = ParameterStatus.VALID; + } + } + }; + report = new BooleanParameter(false, "Report") { + @Override + public void validate(boolean newValue) { + // nothing } }; } @@ -63,7 +88,7 @@ public class MuPlusLambda implements EvolutionaryAlgorithm { @Override public Parameter[] getLocalParameters() { - return new Parameter[] {parents, offspring}; + return new Parameter[] {parents, offspring, report}; } @Override diff --git a/src/jcgp/backend/modules/ea/TournamentSelection.java b/src/jcgp/backend/modules/ea/TournamentSelection.java index 3c4a539..32ac54d 100644 --- a/src/jcgp/backend/modules/ea/TournamentSelection.java +++ b/src/jcgp/backend/modules/ea/TournamentSelection.java @@ -19,8 +19,8 @@ public class TournamentSelection implements EvolutionaryAlgorithm { public TournamentSelection() { tournament = new IntegerParameter(1, "Tournament size") { @Override - protected void validate(int newValue) { - + public void validate(int newValue) { + // TODO this } }; diff --git a/src/jcgp/backend/parameters/BooleanParameter.java b/src/jcgp/backend/parameters/BooleanParameter.java index db78419..43825be 100644 --- a/src/jcgp/backend/parameters/BooleanParameter.java +++ b/src/jcgp/backend/parameters/BooleanParameter.java @@ -11,6 +11,13 @@ public abstract class BooleanParameter extends Parameter { this.value = new SimpleBooleanProperty(value); } + /** + * Simple BooleanParameter constructor, + * + * + * @param value + * @param name + */ public BooleanParameter(boolean value, String name) { super(name, false, false); this.value = new SimpleBooleanProperty(value); @@ -26,7 +33,7 @@ public abstract class BooleanParameter extends Parameter { } } - protected abstract void validate(boolean newValue); + public abstract void validate(boolean newValue); public SimpleBooleanProperty valueProperty() { return value; diff --git a/src/jcgp/backend/parameters/DoubleParameter.java b/src/jcgp/backend/parameters/DoubleParameter.java index 2b98991..53551f5 100644 --- a/src/jcgp/backend/parameters/DoubleParameter.java +++ b/src/jcgp/backend/parameters/DoubleParameter.java @@ -30,6 +30,6 @@ public abstract class DoubleParameter extends Parameter { return value; } - protected abstract void validate(double newValue); + public abstract void validate(double newValue); } diff --git a/src/jcgp/backend/parameters/IntegerParameter.java b/src/jcgp/backend/parameters/IntegerParameter.java index 1127817..68095d9 100644 --- a/src/jcgp/backend/parameters/IntegerParameter.java +++ b/src/jcgp/backend/parameters/IntegerParameter.java @@ -31,6 +31,6 @@ public abstract class IntegerParameter extends Parameter { return value; } - protected abstract void validate(int newValue); + public abstract void validate(int newValue); } diff --git a/src/jcgp/backend/parameters/Parameter.java b/src/jcgp/backend/parameters/Parameter.java index 26bc8f1..ddd5d5b 100644 --- a/src/jcgp/backend/parameters/Parameter.java +++ b/src/jcgp/backend/parameters/Parameter.java @@ -4,7 +4,7 @@ import javafx.beans.property.Property; public abstract class Parameter { - protected boolean monitor, critical; + protected boolean monitor, critical, reset = false; protected ParameterStatus status = ParameterStatus.VALID; @@ -24,6 +24,10 @@ public abstract class Parameter { return critical; } + public boolean requiresReset() { + return critical || reset; + } + public String getName() { return name; } @@ -33,5 +37,5 @@ public abstract class Parameter { } public abstract Property valueProperty(); - + } diff --git a/src/jcgp/backend/parameters/ParameterStatus.java b/src/jcgp/backend/parameters/ParameterStatus.java index ed235d4..86abe33 100644 --- a/src/jcgp/backend/parameters/ParameterStatus.java +++ b/src/jcgp/backend/parameters/ParameterStatus.java @@ -1,7 +1,7 @@ package jcgp.backend.parameters; public enum ParameterStatus { - INVALID, WARNING, VALID; + INVALID, WARNING, WARNING_RESET, VALID; private String details; diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java index 41ba06e..c7493b9 100644 --- a/src/jcgp/backend/population/Chromosome.java +++ b/src/jcgp/backend/population/Chromosome.java @@ -310,6 +310,7 @@ public class Chromosome { } public void printNodes() { + // TODO make this proper int arity = resources.getInt("arity"); for (int r = 0; r < (resources.getInt("rows")); r++) { diff --git a/src/jcgp/gui/GUI.java b/src/jcgp/gui/GUI.java index 0902b21..f7aa25d 100644 --- a/src/jcgp/gui/GUI.java +++ b/src/jcgp/gui/GUI.java @@ -53,12 +53,38 @@ public class GUI extends Application { private GUIConsole console = new GUIConsole(); private SettingsPane settings; - private Service cgpService; - private boolean evolving = false; private Object printLock = new Object(); + private Service cgpService = new Service () { + @Override + protected Task createTask() { + Task t = new Task() { + @Override + protected Void call() throws Exception { + while (!isCancelled() && !cgp.isFinished()) { + synchronized (printLock) { + Platform.runLater(consoleFlush); + cgp.nextGeneration(); + printLock.wait(); + } + } + if (cgp.isFinished()) { + Platform.runLater(new Runnable() { + @Override + public void run() { + runningMode(false); + } + }); + } + return null; + } + }; + return t; + } + }; + private Runnable consoleFlush = new Runnable() { @Override public void run() { @@ -80,27 +106,6 @@ public class GUI extends Application { public void start(Stage primaryStage) throws Exception { resources.setConsole(console); - cgpService = new Service () { - @Override - protected Task createTask() { - - Task t = new Task() { - @Override - protected Void call() throws Exception { - while (!isCancelled()) { - Platform.runLater(consoleFlush); - synchronized (printLock) { - cgp.nextGeneration(); - printLock.wait(); - } - } - return null; - } - }; - return t; - } - }; - /* * Instantiate the various GUI elements here. * @@ -167,45 +172,68 @@ public class GUI extends Application { chromosomeTabs.setDisable(value); } - public void disable(boolean value) { - chromosomeTabs.setDisable(value); - settings.disableSettings(value); - } - - public void playPause() { - if (!evolving) { - disable(true); - unlockOutputs(); - evolving = true; - cgpService.restart(); - } else { - disable(false); - updateNodeGrids(); - evolving = false; - cgpService.cancel(); - relockOutputs(); + public void runPause() { + if (!cgp.isFinished() && settings.areParametersValid()) { + if (!evolving) { + runningMode(true); + cgpService.restart(); + } else { + cgpService.cancel(); + runningMode(false); + } } } public void step() { - if (!evolving) { - Thread t = new Thread(new Task() { + if (!evolving && !cgp.isFinished() && settings.areParametersValid()) { + if (settings.isResetRequired()) { + reset(); + } + unlockOutputs(); + Task task = new Task() { @Override protected Void call() throws Exception { - unlockOutputs(); cgp.nextGeneration(); - console.flush(); - updateNodeGrids(); - relockOutputs(); + Platform.runLater(consoleFlush); return null; } - }); + }; + Thread t = new Thread(task); t.start(); + try { + t.join(); + } catch (InterruptedException e) { + // nothing + } finally { + updateNodeGrids(); + relockOutputs(); + } } } public void reset() { - cgp.reset(); - makeChromosomeTabPane(); + if (!evolving && settings.areParametersValid()) { + settings.applyParameters(); + cgp.reset(); + makeChromosomeTabPane(); + settings.revalidateParameters(); + } + } + + private void runningMode(boolean value) { + chromosomeTabs.setDisable(value); + settings.disableSettings(value); + if (value) { + unlockOutputs(); + settings.getRunButton().setText("Pause"); + if (settings.isResetRequired()) { + reset(); + } + } else { + updateNodeGrids(); + relockOutputs(); + settings.getRunButton().setText("Run"); + } + evolving = value; } } diff --git a/src/jcgp/gui/console/GUIConsole.java b/src/jcgp/gui/console/GUIConsole.java index 8fdb1a5..d8625f5 100644 --- a/src/jcgp/gui/console/GUIConsole.java +++ b/src/jcgp/gui/console/GUIConsole.java @@ -10,15 +10,14 @@ import jcgp.gui.GUI; public class GUIConsole extends AnchorPane implements Console { private boolean dragging; - private TextArea textArea = new TextArea("Welcome to JCGP!\n"); + private TextArea textArea = new TextArea("Welcome to JCGP!"); private StringBuffer printBuffer = new StringBuffer(); public GUIConsole() { super(); textArea.setEditable(false); - textArea.setWrapText(true); - + setResizeListeners(); AnchorPane.setTopAnchor(textArea, GUI.RESIZE_MARGIN); @@ -91,7 +90,7 @@ public class GUIConsole extends AnchorPane implements Console { @Override public void println(String s) { - printBuffer.append(s + "\n"); + printBuffer.append("\n" + s); } @Override diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java index 41b1bba..cb066b7 100644 --- a/src/jcgp/gui/settings/SettingsPane.java +++ b/src/jcgp/gui/settings/SettingsPane.java @@ -32,17 +32,16 @@ public class SettingsPane extends AnchorPane { private VBox mainContainer; private VBox bpPane, eaPane, mutatorPane, ffPane, nfPane; - private ArrayList parameters = new ArrayList(); - private GUI gui; + private Button runPause; + private ArrayList parameters = new ArrayList(); + private boolean dragging = false; public SettingsPane(JCGP cgp, GUI gui) { super(); - - this.gui = gui; - + setResizeListeners(); mainContainer = new VBox(8); @@ -85,22 +84,22 @@ public class SettingsPane extends AnchorPane { bpPane.getChildren().add(header); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("rows"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("columns"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("inputs"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("outputs"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("levelsBack"))); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("rows"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("columns"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("inputs"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("outputs"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("levelsBack"), this)); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("popSize"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("generations"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("runs"))); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("popSize"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("generations"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("runs"), this)); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("currentGen"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("currentRun"))); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("currentGen"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("currentRun"), this)); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("maxFitness"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("seed"))); - parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("report"))); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("maxFitness"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("seed"), this)); + parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("report"), this)); bpPane.getChildren().addAll(parameters); @@ -238,43 +237,41 @@ public class SettingsPane extends AnchorPane { controls.setFillWidth(true); final HBox flowButtons = new HBox(2); - final Button play = new Button("Run"); - - play.setOnAction(new EventHandler() { + runPause = new Button("Run"); + runPause.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - if (play.getText() == "Run") { - if (isResetRequired()) { - resetExperiment(); - } - play.setText("Pause"); - } else { - play.setText("Run"); - } - gui.playPause(); + gui.runPause(); } }); Button step = new Button("Step"); - step.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - if (isResetRequired()) { - resetExperiment(); - } gui.step(); } }); - flowButtons.getChildren().addAll(play, step); + Button reset = new Button("Reset"); + reset.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + gui.reset(); + } + }); + + flowButtons.getChildren().addAll(runPause, step, reset); - HBox.setHgrow(play, Priority.ALWAYS); - play.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(runPause, Priority.ALWAYS); + runPause.setMaxWidth(Double.MAX_VALUE); HBox.setHgrow(step, Priority.ALWAYS); step.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(reset, Priority.ALWAYS); + reset.setMaxWidth(Double.MAX_VALUE); + controls.getChildren().add(flowButtons); mainContainer.getChildren().add(controls); @@ -288,11 +285,12 @@ public class SettingsPane extends AnchorPane { parameters.removeAll(vb.getChildren()); vb.getChildren().clear(); for (int i = 0; i < newParameters.length; i++) { - GUIParameter gp = GUIParameter.create(newParameters[i]); + GUIParameter gp = GUIParameter.create(newParameters[i], this); parameters.add(gp); vb.getChildren().add(gp); } + revalidateParameters(); } private void refreshFunctions(final FunctionSet fs, VBox vb) { @@ -377,21 +375,38 @@ public class SettingsPane extends AnchorPane { * * @return true if the experiment needs to be reset, false otherwise. */ - private boolean isResetRequired() { - boolean reset = false; + public boolean isResetRequired() { for (GUIParameter parameter : parameters) { - reset |= parameter.requiresReset(); + if (parameter.requiresReset()) { + return true; + } } - System.out.println("reset: " + reset); - return reset; + return false; } - private void resetExperiment() { + public boolean areParametersValid() { for (GUIParameter parameter : parameters) { - parameter.applyValue(); + if (!parameter.isValid()) { + return false; + } } - gui.reset(); - + return true; + } + + public void revalidateParameters() { + for (GUIParameter parameter : parameters) { + parameter.validate(); + } + } + + public void applyParameters() { + for (GUIParameter parameter : parameters) { + parameter.applyValue(); + } + } + + public Button getRunButton() { + return runPause; } diff --git a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java index da564f7..fc66e7d 100644 --- a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java @@ -6,12 +6,13 @@ import javafx.scene.control.CheckBox; import jcgp.backend.parameters.BooleanParameter; import jcgp.backend.parameters.ParameterStatus; import jcgp.gui.GUI; +import jcgp.gui.settings.SettingsPane; public class GUIBooleanParameter extends GUIParameter { private boolean originalValue; - GUIBooleanParameter(final BooleanParameter parameter) { + GUIBooleanParameter(final BooleanParameter parameter, final SettingsPane sp) { super(); this.parameter = parameter; @@ -32,18 +33,8 @@ public class GUIBooleanParameter extends GUIParameter { ObservableValue observable, Boolean oldValue, Boolean newValue) { parameter.set(newValue); - if (parameter.getStatus() == ParameterStatus.INVALID) { - valueControl.setStyle(GUI.INVALID_PARAMETER_STYLE); - valueControl.setTooltip(tooltip); - tooltip.setText(parameter.getStatus().getDetails()); - } else if (parameter.getStatus() == ParameterStatus.WARNING) { - valueControl.setStyle(GUI.WARNING_PARAMETER_STYLE); - valueControl.setTooltip(tooltip); - tooltip.setText(parameter.getStatus().getDetails()); - } else { - valueControl.setStyle(GUI.VALID_PARAMETER_STYLE); - valueControl.setTooltip(null); - } + setValidityStyle(); + sp.revalidateParameters(); } }); } @@ -60,7 +51,8 @@ public class GUIBooleanParameter extends GUIParameter { @Override public boolean requiresReset() { - return parameter.isCritical() && ((BooleanParameter) parameter).get() != originalValue; + return (parameter.isCritical() && ((BooleanParameter) parameter).get() != originalValue) + || parameter.getStatus() == ParameterStatus.WARNING_RESET; } @Override @@ -68,4 +60,27 @@ public class GUIBooleanParameter extends GUIParameter { originalValue = ((BooleanParameter) parameter).get(); } + /** + * @param parameter + */ + private void setValidityStyle() { + if (parameter.getStatus() == ParameterStatus.INVALID) { + valueControl.setStyle(GUI.INVALID_PARAMETER_STYLE); + valueControl.setTooltip(tooltip); + tooltip.setText(parameter.getStatus().getDetails()); + } else if (parameter.getStatus() == ParameterStatus.WARNING || parameter.getStatus() == ParameterStatus.WARNING_RESET) { + valueControl.setStyle(GUI.WARNING_PARAMETER_STYLE); + valueControl.setTooltip(tooltip); + tooltip.setText(parameter.getStatus().getDetails()); + } else { + valueControl.setStyle(GUI.VALID_PARAMETER_STYLE); + valueControl.setTooltip(null); + } + } + + @Override + public void validate() { + ((BooleanParameter) parameter).validate(((BooleanParameter) parameter).get()); + setValidityStyle(); + } } diff --git a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java index a1b4526..190f4b7 100644 --- a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java @@ -11,12 +11,13 @@ import javafx.scene.text.Text; import jcgp.backend.parameters.DoubleParameter; import jcgp.backend.parameters.ParameterStatus; import jcgp.gui.GUI; +import jcgp.gui.settings.SettingsPane; public class GUIDoubleParameter extends GUIParameter { private double originalValue; - GUIDoubleParameter(final DoubleParameter parameter) { + GUIDoubleParameter(final DoubleParameter parameter, final SettingsPane sp) { super(); this.parameter = parameter; @@ -54,18 +55,8 @@ public class GUIDoubleParameter extends GUIParameter { String oldValue, String newValue) { if (!newValue.isEmpty()) { parameter.set(Double.parseDouble(newValue)); - if (parameter.getStatus() == ParameterStatus.INVALID) { - valueControl.setStyle(GUI.INVALID_PARAMETER_STYLE); - valueControl.setTooltip(tooltip); - tooltip.setText(parameter.getStatus().getDetails()); - } else if (parameter.getStatus() == ParameterStatus.WARNING) { - valueControl.setStyle(GUI.WARNING_PARAMETER_STYLE); - valueControl.setTooltip(tooltip); - tooltip.setText(parameter.getStatus().getDetails()); - } else { - valueControl.setStyle(GUI.VALID_PARAMETER_STYLE); - valueControl.setTooltip(null); - } + setValidityStyle(); + sp.revalidateParameters(); } } @@ -93,7 +84,8 @@ public class GUIDoubleParameter extends GUIParameter { @Override public boolean requiresReset() { - return parameter.isCritical() && ((DoubleParameter) parameter).get() != originalValue; + return (parameter.isCritical() && ((DoubleParameter) parameter).get() != originalValue) + || parameter.getStatus() == ParameterStatus.WARNING_RESET; } @Override @@ -101,4 +93,25 @@ public class GUIDoubleParameter extends GUIParameter { originalValue = ((DoubleParameter) parameter).get(); } + @Override + public void validate() { + ((DoubleParameter) parameter).validate(((DoubleParameter) parameter).get()); + setValidityStyle(); + } + + private void setValidityStyle() { + if (parameter.getStatus() == ParameterStatus.INVALID) { + valueControl.setStyle(GUI.INVALID_PARAMETER_STYLE); + valueControl.setTooltip(tooltip); + tooltip.setText(parameter.getStatus().getDetails()); + } else if (parameter.getStatus() == ParameterStatus.WARNING || parameter.getStatus() == ParameterStatus.WARNING_RESET) { + valueControl.setStyle(GUI.WARNING_PARAMETER_STYLE); + valueControl.setTooltip(tooltip); + tooltip.setText(parameter.getStatus().getDetails()); + } else { + valueControl.setStyle(GUI.VALID_PARAMETER_STYLE); + valueControl.setTooltip(null); + } + } + } diff --git a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java index bf1a61e..a2040d7 100644 --- a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java @@ -11,12 +11,13 @@ import javafx.scene.text.Text; import jcgp.backend.parameters.IntegerParameter; import jcgp.backend.parameters.ParameterStatus; import jcgp.gui.GUI; +import jcgp.gui.settings.SettingsPane; public class GUIIntegerParameter extends GUIParameter { private int originalValue; - GUIIntegerParameter(final IntegerParameter parameter) { + GUIIntegerParameter(final IntegerParameter parameter, final SettingsPane sp) { super(); this.parameter = parameter; @@ -54,18 +55,8 @@ public class GUIIntegerParameter extends GUIParameter { String oldValue, String newValue) { if (!newValue.isEmpty()) { parameter.set(Integer.parseInt(newValue)); - if (parameter.getStatus() == ParameterStatus.INVALID) { - valueControl.setStyle(GUI.INVALID_PARAMETER_STYLE); - valueControl.setTooltip(tooltip); - tooltip.setText(parameter.getStatus().getDetails()); - } else if (parameter.getStatus() == ParameterStatus.WARNING) { - valueControl.setStyle(GUI.WARNING_PARAMETER_STYLE); - valueControl.setTooltip(tooltip); - tooltip.setText(parameter.getStatus().getDetails()); - } else { - valueControl.setStyle(GUI.VALID_PARAMETER_STYLE); - valueControl.setTooltip(null); - } + setValidityStyle(); + sp.revalidateParameters(); } } @@ -92,7 +83,9 @@ public class GUIIntegerParameter extends GUIParameter { @Override public boolean requiresReset() { - return parameter.isCritical() && ((IntegerParameter) parameter).get() != originalValue; + // true if critical and the value has changed, or it requires a reset anyway + return (parameter.isCritical() && ((IntegerParameter) parameter).get() != originalValue) + || parameter.getStatus() == ParameterStatus.WARNING_RESET; } @Override @@ -100,4 +93,25 @@ public class GUIIntegerParameter extends GUIParameter { originalValue = ((IntegerParameter) parameter).get(); } + @Override + public void validate() { + ((IntegerParameter) parameter).validate(((IntegerParameter) parameter).get()); + setValidityStyle(); + } + + private void setValidityStyle() { + if (parameter.getStatus() == ParameterStatus.INVALID) { + valueControl.setStyle(GUI.INVALID_PARAMETER_STYLE); + valueControl.setTooltip(tooltip); + tooltip.setText(parameter.getStatus().getDetails()); + } else if (parameter.getStatus() == ParameterStatus.WARNING || parameter.getStatus() == ParameterStatus.WARNING_RESET) { + valueControl.setStyle(GUI.WARNING_PARAMETER_STYLE); + valueControl.setTooltip(tooltip); + tooltip.setText(parameter.getStatus().getDetails()); + } else { + valueControl.setStyle(GUI.VALID_PARAMETER_STYLE); + valueControl.setTooltip(null); + } + } + } diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java index 9d6f07a..da2fe86 100644 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIParameter.java @@ -14,6 +14,8 @@ import jcgp.backend.parameters.BooleanParameter; import jcgp.backend.parameters.DoubleParameter; import jcgp.backend.parameters.IntegerParameter; import jcgp.backend.parameters.Parameter; +import jcgp.backend.parameters.ParameterStatus; +import jcgp.gui.settings.SettingsPane; public abstract class GUIParameter extends HBox { @@ -59,15 +61,23 @@ public abstract class GUIParameter extends HBox { public abstract void applyValue(); - public static GUIParameter create(Parameter parameter) { + public abstract void validate(); + + public static GUIParameter create(Parameter parameter, SettingsPane sp) { if (parameter instanceof IntegerParameter) { - return new GUIIntegerParameter((IntegerParameter) parameter); + return new GUIIntegerParameter((IntegerParameter) parameter, sp); } else if (parameter instanceof DoubleParameter) { - return new GUIDoubleParameter((DoubleParameter) parameter); + return new GUIDoubleParameter((DoubleParameter) parameter, sp); } else if (parameter instanceof BooleanParameter) { - return new GUIBooleanParameter((BooleanParameter) parameter); + return new GUIBooleanParameter((BooleanParameter) parameter, sp); } else { throw new ClassCastException("No GUIParameter subclass exists for argument of type " + parameter.getClass()); } } + + public boolean isValid() { + return parameter.getStatus() == ParameterStatus.VALID + || parameter.getStatus() == ParameterStatus.WARNING + || parameter.getStatus() == ParameterStatus.WARNING_RESET; + } } -- cgit v1.2.3