aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp')
-rw-r--r--src/jcgp/JCGP.java237
-rw-r--r--src/jcgp/backend/modules/Module.java6
-rw-r--r--src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java3
-rw-r--r--src/jcgp/backend/modules/ea/MuPlusLambda.java57
-rw-r--r--src/jcgp/backend/modules/ea/TournamentSelection.java18
-rw-r--r--src/jcgp/backend/modules/fitness/TestCaseEvaluator.java6
-rw-r--r--src/jcgp/backend/modules/mutator/PointMutator.java19
-rw-r--r--src/jcgp/backend/parameters/BooleanParameter.java10
-rw-r--r--src/jcgp/backend/parameters/DoubleParameter.java10
-rw-r--r--src/jcgp/backend/parameters/IntegerParameter.java13
-rw-r--r--src/jcgp/backend/parameters/Parameter.java16
-rw-r--r--src/jcgp/backend/parameters/ParameterStatus.java16
-rw-r--r--src/jcgp/backend/population/Chromosome.java10
-rw-r--r--src/jcgp/backend/population/Population.java53
-rw-r--r--src/jcgp/gui/GUI.java34
-rw-r--r--src/jcgp/gui/settings/SettingsPane.java58
-rw-r--r--src/jcgp/gui/settings/parameters/GUIBooleanParameter.java63
-rw-r--r--src/jcgp/gui/settings/parameters/GUIDoubleParameter.java89
-rw-r--r--src/jcgp/gui/settings/parameters/GUIIntegerParameter.java84
-rw-r--r--src/jcgp/gui/settings/parameters/GUIParameter.java21
20 files changed, 556 insertions, 267 deletions
diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java
index 7451d4f..0c75f2b 100644
--- a/src/jcgp/JCGP.java
+++ b/src/jcgp/JCGP.java
@@ -25,6 +25,7 @@ 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.backend.population.Population;
import jcgp.gui.console.Console;
@@ -114,26 +115,143 @@ public class JCGP {
}
private void createBaseParameters() {
- parameters.put("rows", new IntegerParameter(8, "Rows"));
- parameters.put("columns", new IntegerParameter(9, "Columns"));
- parameters.put("inputs", new IntegerParameter(3, "Inputs"));
- parameters.put("outputs", new IntegerParameter(3, "Outputs"));
- parameters.put("popSize", new IntegerParameter(5, "Population"));
- parameters.put("levelsBack", new IntegerParameter(2, "Levels back"));
+ parameters.put("rows", new IntegerParameter(8, "Rows", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= 0) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Chromosome must have at least 1 row.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("columns", new IntegerParameter(9, "Columns", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= 0) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Chromosome must have at least 1 column.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("inputs", new IntegerParameter(3, "Inputs", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= 0) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Chromosome must have at least 1 input.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("outputs", new IntegerParameter(3, "Outputs", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= 0) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Chromosome must have at least 1 output.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("popSize", new IntegerParameter(5, "Population", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= 0) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Population size must be at least 1.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("levelsBack", new IntegerParameter(2, "Levels back", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= 0) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Levels back must be at least 1.");
+ } else if (newValue > getInt("columns")) {
+ status = ParameterStatus.INVALID;
+ status.setDetails("Levels back must be less than or equal to the number of columns.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
- IntegerParameter nodes = new IntegerParameter(1, "Nodes", true, true, false);
+ IntegerParameter nodes = new IntegerParameter(1, "Nodes", true, false) {
+ @Override
+ protected void validate(int newValue) {
+ // blank
+ }
+ };
nodes.valueProperty().bind(((SimpleIntegerProperty) ((IntegerParameter) parameters.get("rows")).valueProperty()).multiply((SimpleIntegerProperty) ((IntegerParameter) parameters.get("columns")).valueProperty()));
parameters.put("nodes", nodes);
- parameters.put("generations", new IntegerParameter(1000000, "Generations"));
- parameters.put("currentGen", new IntegerParameter(1, "Generation", true, false, false));
-
- parameters.put("runs", new IntegerParameter(5, "Runs"));
- parameters.put("currentRun", new IntegerParameter(1, "Run", true, false, false));
+ parameters.put("generations", new IntegerParameter(1000000, "Generations") {
+ @Override
+ protected 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;
+ status.setDetails("Setting generations to less than the current generation will cause the experiment to restart.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("currentGen", new IntegerParameter(1, "Generation", true, false) {
+ @Override
+ protected void validate(int newValue) {
+ // blank
+ }
+ });
- parameters.put("arity", new IntegerParameter(0, "Max arity", false, true, false));
+ parameters.put("runs", new IntegerParameter(5, "Runs") {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue <= getInt("currentRun")) {
+ status = ParameterStatus.WARNING;
+ status.setDetails("Setting runs to less than the current run will cause the experiment to restart.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
+ parameters.put("currentRun", new IntegerParameter(1, "Run", true, false) {
+ @Override
+ protected void validate(int newValue) {
+ // blank
+ }
+ });
+
+ parameters.put("arity", new IntegerParameter(0, "Max arity", true, false) {
+ @Override
+ protected void validate(int newValue) {
+ // blank
+ }
+ });
+ parameters.put("maxFitness", new IntegerParameter(6, "Max fitness", true, true) {
+ @Override
+ protected void validate(int newValue) {
+ // blank
+ }
+ });
- IntegerParameter seed = new IntegerParameter(123, "Seed");
+ IntegerParameter seed = new IntegerParameter(123, "Seed", false, true) {
+ @Override
+ protected void validate(int newValue) {
+ status = ParameterStatus.VALID;
+ }
+ };
seed.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(
@@ -144,50 +262,17 @@ public class JCGP {
});
parameters.put("seed", seed);
- parameters.put("report", new IntegerParameter(1, "Report", false, false, false));
- }
-
- private boolean validateBaseParameters() {
- boolean valid = true;
-
- if (getInt("rows") <= 0) {
- valid = false;
- println("Error: number of rows must be greater than 0.");
- }
- if (getInt("columns") <= 0) {
- valid = false;
- println("Error: number of columns must be greater than 0.");
- }
- if (getInt("inputs") <= 0) {
- valid = false;
- println("Error: number of inputs must be greater than 0.");
- }
- if (getInt("outputs") <= 0) {
- println("Error: number of outputs must be greater than 0.");
- valid = false;
- }
- if (getInt("popSize") <= 0) {
- println("Error: population size must be greater than 0.");
- valid = false;
- }
- if (getInt("levelsBack") <= 0 || getInt("levelsBack") > getInt("columns")) {
- println("Error: levels back must be greater than 0 and no greater than the number of columns.");
- valid = false;
- }
- if (getInt("generations") <= 0) {
- println("Error: number of generations must be greater than 0.");
- valid = false;
- }
- if (getInt("runs") <= 0) {
- println("Error: number of runs must be greater than 0.");
- valid = false;
- }
- if (getInt("report") < 0) {
- println("Error: report frequency must not be smaller than 0.");
- valid = false;
- }
-
- return valid;
+ parameters.put("report", new IntegerParameter(1, "Report", false, false) {
+ @Override
+ protected void validate(int newValue) {
+ if (newValue > getInt("generations")) {
+ status = ParameterStatus.WARNING;
+ status.setDetails("No reports will be printed.");
+ } else {
+ status = ParameterStatus.VALID;
+ }
+ }
+ });
}
/**
@@ -310,6 +395,8 @@ public class JCGP {
* the population of chromosomes
*/
private Population population;
+
+ private boolean solutionFound = false;
public JCGP() {
@@ -323,21 +410,14 @@ public class JCGP {
fitnessFunction = fitnessFunctions[0];
resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}),
- new TestCase(new Integer[]{1, 12, 4}, new Integer[]{6, 21, 2}));
+ new TestCase(new Integer[]{4, 7, 4}, new Integer[]{6, 21, 2}));
}
-
- public void remakePopulation() {
- population = new Population(resources);
- }
-
-
public Resources getResources() {
return resources;
}
-
public Population getPopulation() {
return population;
}
@@ -415,22 +495,33 @@ public class JCGP {
}
public void nextGeneration() {
-
fitnessFunction.evaluate(population, resources);
- evolutionaryAlgorithm.evolve(population, mutator, resources);
- if (evolutionaryAlgorithm.getFittestChromosome().getFitness() >= 6) {
- resources.println("solution found");
- evolutionaryAlgorithm.getFittestChromosome().printNodes();
+ 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: " + evolutionaryAlgorithm.getFittestChromosome().getFitness());
+ resources.println("Generation: " + resources.getInt("currentGen") + ", fitness: " + population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness());
+ resources.set("currentGen", resources.getInt("currentGen") + 1);
}
- resources.set("currentGen", resources.getInt("currentGen") + 1);
+
+ evolutionaryAlgorithm.evolve(population, mutator, resources);
}
public void start() {
while (resources.getInt("currentGen") <= resources.getInt("generations")) {
nextGeneration();
+
+ if (solutionFound) {
+ break;
+ }
}
}
+
+ public void reset() {
+ solutionFound = false;
+ population = new Population(resources);
+ }
+
}
diff --git a/src/jcgp/backend/modules/Module.java b/src/jcgp/backend/modules/Module.java
index f9114de..82c3d80 100644
--- a/src/jcgp/backend/modules/Module.java
+++ b/src/jcgp/backend/modules/Module.java
@@ -1,11 +1,11 @@
package jcgp.backend.modules;
-import java.util.HashMap;
-
import jcgp.JCGP.Resources;
import jcgp.backend.parameters.Parameter;
public interface Module {
- public HashMap<String, Parameter> getLocalParameters();
+
+ public Parameter[] getLocalParameters();
+
public ModuleStatus getStatus(Resources resources);
}
diff --git a/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java b/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java
index ce457ef..7719111 100644
--- a/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java
+++ b/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java
@@ -3,13 +3,12 @@ package jcgp.backend.modules.ea;
import jcgp.JCGP.Resources;
import jcgp.backend.modules.Module;
import jcgp.backend.modules.mutator.Mutator;
-import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Population;
public interface EvolutionaryAlgorithm extends Module {
public abstract void evolve(Population population, Mutator mutator, Resources parameters);
- public abstract Chromosome getFittestChromosome();
+ public abstract int getFittestChromosome();
}
diff --git a/src/jcgp/backend/modules/ea/MuPlusLambda.java b/src/jcgp/backend/modules/ea/MuPlusLambda.java
index fcfba05..22a0876 100644
--- a/src/jcgp/backend/modules/ea/MuPlusLambda.java
+++ b/src/jcgp/backend/modules/ea/MuPlusLambda.java
@@ -1,13 +1,10 @@
package jcgp.backend.modules.ea;
-import java.util.HashMap;
-
import jcgp.JCGP.Resources;
import jcgp.backend.modules.ModuleStatus;
import jcgp.backend.modules.mutator.Mutator;
import jcgp.backend.parameters.IntegerParameter;
import jcgp.backend.parameters.Parameter;
-import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Population;
/**
@@ -19,52 +16,54 @@ import jcgp.backend.population.Population;
*/
public class MuPlusLambda implements EvolutionaryAlgorithm {
- private Chromosome fittestChromosome;
+ private int fittestChromosome;
private IntegerParameter parents, offspring;
-
- private HashMap<String, Parameter> localParameters;
-
- public MuPlusLambda() {
- parents = new IntegerParameter(1, "Parents");
- offspring = new IntegerParameter(4, "Offspring");
-
- localParameters = new HashMap<String, Parameter>();
- localParameters.put("mu", parents);
- localParameters.put("lambda", offspring);
+ public MuPlusLambda() {
+ parents = new IntegerParameter(1, "Parents") {
+ @Override
+ protected void validate(int newValue) {
+
+ }
+ };
+ offspring = new IntegerParameter(4, "Offspring") {
+ @Override
+ protected void validate(int newValue) {
+
+ }
+ };
}
@Override
- public void evolve(Population population, Mutator mutator, Resources parameters) {
+ public void evolve(Population population, Mutator mutator, Resources resources) {
+ // TODO actually use parents and offspring
// select fittest chromosome
- int fittest = 0;
+ fittestChromosome = 0;
- for (int i = 1; i < parameters.getInt("popSize"); i++) {
- if (population.getChromosome(i).getFitness() >= population.getChromosome(fittest).getFitness()) {
- fittest = i;
+ for (int i = 1; i < resources.getInt("popSize"); i++) {
+ if (population.getChromosome(i).getFitness() >= population.getChromosome(fittestChromosome).getFitness()) {
+ fittestChromosome = i;
}
}
- fittestChromosome = population.getChromosome(fittest);
- population.setBestIndividual(fittest);
+
// create copies of fittest chromosome, mutate them
- Chromosome fc = population.getChromosome(fittest);
- for (int i = 0; i < parameters.getInt("popSize"); i++) {
- if (i != fittest) {
- population.getChromosome(i).copyConnections(fc);
- mutator.mutate(population.getChromosome(i), parameters);
+ for (int i = 0; i < resources.getInt("popSize"); i++) {
+ if (i != fittestChromosome) {
+ population.copyChromosome(fittestChromosome, i);
+ mutator.mutate(population.getChromosome(i), resources);
}
}
}
@Override
- public Chromosome getFittestChromosome() {
+ public int getFittestChromosome() {
return fittestChromosome;
}
@Override
- public HashMap<String, Parameter> getLocalParameters() {
- return localParameters;
+ public Parameter[] getLocalParameters() {
+ return new Parameter[] {parents, offspring};
}
@Override
diff --git a/src/jcgp/backend/modules/ea/TournamentSelection.java b/src/jcgp/backend/modules/ea/TournamentSelection.java
index 6cbaa45..3c4a539 100644
--- a/src/jcgp/backend/modules/ea/TournamentSelection.java
+++ b/src/jcgp/backend/modules/ea/TournamentSelection.java
@@ -7,39 +7,43 @@ import jcgp.backend.modules.ModuleStatus;
import jcgp.backend.modules.mutator.Mutator;
import jcgp.backend.parameters.IntegerParameter;
import jcgp.backend.parameters.Parameter;
-import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Population;
public class TournamentSelection implements EvolutionaryAlgorithm {
- private Chromosome fittestChromosome;
+ private int fittestChromosome;
private IntegerParameter tournament;
private HashMap<String, Parameter> localParameters;
public TournamentSelection() {
- tournament = new IntegerParameter(1, "Tournament size");
+ tournament = new IntegerParameter(1, "Tournament size") {
+ @Override
+ protected void validate(int newValue) {
+
+ }
+ };
localParameters = new HashMap<String, Parameter>();
localParameters.put("tournament", tournament);
}
@Override
- public HashMap<String, Parameter> getLocalParameters() {
- return localParameters;
+ public Parameter[] getLocalParameters() {
+ return new Parameter[] {tournament};
}
@Override
public void evolve(Population population, Mutator mutator,
Resources parameters) {
tournament.set(tournament.get() + 1);
- fittestChromosome = population.getChromosome(0);
+ fittestChromosome = 0;
// TODO implement this
}
@Override
- public Chromosome getFittestChromosome() {
+ public int getFittestChromosome() {
return fittestChromosome;
}
diff --git a/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java b/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java
index 3b67f28..5ff6973 100644
--- a/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java
+++ b/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java
@@ -1,7 +1,5 @@
package jcgp.backend.modules.fitness;
-import java.util.HashMap;
-
import jcgp.JCGP.Resources;
import jcgp.backend.modules.ModuleStatus;
import jcgp.backend.parameters.Parameter;
@@ -10,7 +8,7 @@ import jcgp.backend.population.Population;
public class TestCaseEvaluator implements FitnessFunction {
@Override
- public void evaluate(Population population, Resources resources) {
+ public void evaluate(Population population, Resources resources) {
// for every chromosome in the population
for (int i = 0; i < resources.getInt("popSize"); i++) {
int fitness = 0;
@@ -29,7 +27,7 @@ public class TestCaseEvaluator implements FitnessFunction {
}
@Override
- public HashMap<String, Parameter> getLocalParameters() {
+ public Parameter[] getLocalParameters() {
return null;
}
diff --git a/src/jcgp/backend/modules/mutator/PointMutator.java b/src/jcgp/backend/modules/mutator/PointMutator.java
index 62d827d..cdac8bb 100644
--- a/src/jcgp/backend/modules/mutator/PointMutator.java
+++ b/src/jcgp/backend/modules/mutator/PointMutator.java
@@ -1,7 +1,5 @@
package jcgp.backend.modules.mutator;
-import java.util.HashMap;
-
import jcgp.backend.function.Function;
import jcgp.backend.modules.ModuleStatus;
import jcgp.backend.parameters.DoubleParameter;
@@ -15,15 +13,16 @@ import jcgp.JCGP.Resources;
public class PointMutator implements Mutator {
private DoubleParameter mutationRate;
- private HashMap<String, Parameter> localParameters;
-
+
private ModuleStatus status = ModuleStatus.READY;
public PointMutator() {
- mutationRate = new DoubleParameter(0.5, "Percent mutation", false, false, false);
-
- localParameters = new HashMap<String, Parameter>();
- localParameters.put("mutRate", mutationRate);
+ mutationRate = new DoubleParameter(0.5, "Percent mutation", false, false) {
+ @Override
+ public void validate(double newValue) {
+ // TODO this
+ }
+ };
}
@Override
@@ -47,8 +46,8 @@ public class PointMutator implements Mutator {
}
@Override
- public HashMap<String, Parameter> getLocalParameters() {
- return localParameters;
+ public Parameter[] getLocalParameters() {
+ return new Parameter[] {mutationRate};
}
@Override
diff --git a/src/jcgp/backend/parameters/BooleanParameter.java b/src/jcgp/backend/parameters/BooleanParameter.java
index d5904cd..db78419 100644
--- a/src/jcgp/backend/parameters/BooleanParameter.java
+++ b/src/jcgp/backend/parameters/BooleanParameter.java
@@ -2,17 +2,17 @@ package jcgp.backend.parameters;
import javafx.beans.property.SimpleBooleanProperty;
-public class BooleanParameter extends Parameter {
+public abstract class BooleanParameter extends Parameter {
private SimpleBooleanProperty value;
- public BooleanParameter(boolean value, String name, boolean monitor, boolean hidden, boolean critical) {
- super(name, monitor, hidden, critical);
+ public BooleanParameter(boolean value, String name, boolean monitor, boolean critical) {
+ super(name, monitor, critical);
this.value = new SimpleBooleanProperty(value);
}
public BooleanParameter(boolean value, String name) {
- super(name, false, false, true);
+ super(name, false, false);
this.value = new SimpleBooleanProperty(value);
}
@@ -26,6 +26,8 @@ public class BooleanParameter extends Parameter {
}
}
+ protected 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 26031be..2b98991 100644
--- a/src/jcgp/backend/parameters/DoubleParameter.java
+++ b/src/jcgp/backend/parameters/DoubleParameter.java
@@ -2,17 +2,17 @@ package jcgp.backend.parameters;
import javafx.beans.property.SimpleDoubleProperty;
-public class DoubleParameter extends Parameter {
+public abstract class DoubleParameter extends Parameter {
protected SimpleDoubleProperty value;
- public DoubleParameter(double value, String name, boolean monitor, boolean hidden, boolean critical) {
- super(name, monitor, hidden, critical);
+ public DoubleParameter(double value, String name, boolean monitor, boolean critical) {
+ super(name, monitor, critical);
this.value = new SimpleDoubleProperty(value);
}
public DoubleParameter(double value, String name) {
- super(name, false, false, true);
+ super(name, false, false);
this.value = new SimpleDoubleProperty(value);
}
@@ -30,4 +30,6 @@ public class DoubleParameter extends Parameter {
return value;
}
+ protected abstract void validate(double newValue);
+
}
diff --git a/src/jcgp/backend/parameters/IntegerParameter.java b/src/jcgp/backend/parameters/IntegerParameter.java
index dbfa5c5..1127817 100644
--- a/src/jcgp/backend/parameters/IntegerParameter.java
+++ b/src/jcgp/backend/parameters/IntegerParameter.java
@@ -2,17 +2,17 @@ package jcgp.backend.parameters;
import javafx.beans.property.SimpleIntegerProperty;
-public class IntegerParameter extends Parameter {
+public abstract class IntegerParameter extends Parameter {
- protected SimpleIntegerProperty value;
+ private SimpleIntegerProperty value;
- public IntegerParameter(int value, String name, boolean monitor, boolean hidden, boolean critical) {
- super(name, monitor, hidden, critical);
+ public IntegerParameter(int value, String name, boolean monitor, boolean critical) {
+ super(name, monitor, critical);
this.value = new SimpleIntegerProperty(value);
}
public IntegerParameter(int value, String name) {
- super(name, false, false, true);
+ super(name, false, false);
this.value = new SimpleIntegerProperty(value);
}
@@ -22,6 +22,7 @@ public class IntegerParameter extends Parameter {
public void set(int newValue) {
if (!value.isBound()) {
+ validate(newValue);
value.set(newValue);
}
}
@@ -30,4 +31,6 @@ public class IntegerParameter extends Parameter {
return value;
}
+ protected abstract void validate(int newValue);
+
}
diff --git a/src/jcgp/backend/parameters/Parameter.java b/src/jcgp/backend/parameters/Parameter.java
index 2f584a4..26bc8f1 100644
--- a/src/jcgp/backend/parameters/Parameter.java
+++ b/src/jcgp/backend/parameters/Parameter.java
@@ -4,21 +4,18 @@ import javafx.beans.property.Property;
public abstract class Parameter {
- protected boolean hidden, monitor, critical;
+ protected boolean monitor, critical;
+
+ protected ParameterStatus status = ParameterStatus.VALID;
protected String name;
- public Parameter(String name, boolean monitor, boolean hidden, boolean critical) {
+ public Parameter(String name, boolean monitor, boolean critical) {
this.name = name;
- this.hidden = hidden;
this.monitor = monitor;
this.critical = critical;
}
- public boolean isHidden() {
- return hidden;
- }
-
public boolean isMonitor() {
return monitor;
}
@@ -31,5 +28,10 @@ public abstract class Parameter {
return name;
}
+ public ParameterStatus getStatus() {
+ return status;
+ }
+
public abstract Property<?> valueProperty();
+
}
diff --git a/src/jcgp/backend/parameters/ParameterStatus.java b/src/jcgp/backend/parameters/ParameterStatus.java
new file mode 100644
index 0000000..ed235d4
--- /dev/null
+++ b/src/jcgp/backend/parameters/ParameterStatus.java
@@ -0,0 +1,16 @@
+package jcgp.backend.parameters;
+
+public enum ParameterStatus {
+ INVALID, WARNING, VALID;
+
+ private String details;
+
+ public void setDetails(String details) {
+ this.details = details;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+
+}
diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java
index 18ae9bb..41ba06e 100644
--- a/src/jcgp/backend/population/Chromosome.java
+++ b/src/jcgp/backend/population/Chromosome.java
@@ -43,12 +43,12 @@ public class Chromosome {
*/
public Chromosome(Chromosome clone) {
// store a reference to the parameters
- this.resources = clone.getParameters();
+ this.resources = clone.getResources();
// allocate memory for all elements of the chromosome
instantiateElements();
// initialise all connections based on argument
- copyConnections(clone);
+ copyGenes(clone);
}
/**
@@ -102,7 +102,7 @@ public class Chromosome {
/**
* @param clone
*/
- public void copyConnections(Chromosome clone) {
+ public void copyGenes(Chromosome clone) {
int arity = resources.getInt("arity");
// copy nodes - [rows][columns]
@@ -119,7 +119,7 @@ public class Chromosome {
} else if (copyConnection instanceof Node) {
connections[i] = nodes[((Node) copyConnection).getRow()][((Node) copyConnection).getColumn()];
} else {
- System.out.println("Warning: Connection of subtype " + copyConnection.getClass().toString() + " is not explicitly handled by copy constructor.");
+ System.out.println("Error: Connection of subtype " + copyConnection.getClass().toString() + " is not explicitly handled by copy method.");
}
}
// initialise with copied arguments
@@ -329,7 +329,7 @@ public class Chromosome {
}
}
- public Resources getParameters() {
+ public Resources getResources() {
return resources;
}
}
diff --git a/src/jcgp/backend/population/Population.java b/src/jcgp/backend/population/Population.java
index 7049d79..7b62d27 100644
--- a/src/jcgp/backend/population/Population.java
+++ b/src/jcgp/backend/population/Population.java
@@ -6,27 +6,41 @@ import jcgp.JCGP.Resources;
public class Population {
private Chromosome[] chromosomes;
- private int fittest;
+ private Resources resources;
+ /**
+ * Initialise a random population according to the parameters specified
+ * in the resources.
+ *
+ * @param resources the CGP resources
+ */
public Population(Resources resources) {
+ this.resources = resources;
+
chromosomes = new Chromosome[(resources.getInt("popSize"))];
for (int c = 0; c < chromosomes.length; c++) {
chromosomes[c] = new Chromosome(resources);
}
}
+ /**
+ * Initialise a population of copies of the given chromosome.
+ *
+ * @param parent
+ * @param resources
+ */
public Population(Chromosome parent, Resources resources) {
+ this.resources = resources;
+
chromosomes = new Chromosome[(resources.getInt("popSize"))];
- // make a clone for safety
- this.chromosomes[0] = new Chromosome(parent);
// generate the rest of the individuals
- for (int c = 1; c < chromosomes.length; c++) {
- chromosomes[c] = new Chromosome(chromosomes[0]);
+ for (int c = 0; c < chromosomes.length; c++) {
+ chromosomes[c] = new Chromosome(parent);
}
}
/**
- * Returns all chromosomes, parents first, then offspring.
+ * Returns the indexed chromosome.
*
* @param index
* @return
@@ -35,11 +49,30 @@ public class Population {
return chromosomes[index];
}
- public void setBestIndividual(int index) {
- fittest = index;
+ /**
+ * @return a random chromosome from this population.
+ */
+ public Chromosome getRandomChromosome() {
+ return chromosomes[resources.getRandomInt(chromosomes.length)];
}
+
- public Chromosome getBestIndividual() {
- return chromosomes[fittest];
+ /**
+ * Copy a chromosome into a different position.
+ * After this returns, the target chromosome has
+ * identical connections and functions to the source
+ * one, though they are separate instances.
+ *
+ * This method does nothing if source == target.
+ *
+ * @param source
+ * @param target
+ */
+ public void copyChromosome(int source, int target) {
+ if (source != target) {
+ chromosomes[target].copyGenes(chromosomes[source]);
+ }
}
+
+
}
diff --git a/src/jcgp/gui/GUI.java b/src/jcgp/gui/GUI.java
index 7e7f385..0902b21 100644
--- a/src/jcgp/gui/GUI.java
+++ b/src/jcgp/gui/GUI.java
@@ -22,16 +22,16 @@ public class GUI extends Application {
* (no hovering, clicking, dragging or any other form of interaction). */
public static final String NEUTRAL_COLOUR = "#FFFFFF";
public static final String HARD_HIGHLIGHT_COLOUR = "#5496FF";
- // 89AAD6
public static final String MEDIUM_HIGHLIGHT_COLOUR = "#75BAFF";
public static final String SOFT_HIGHLIGHT_COLOUR = "#C7DFFF";
- // BDFFC2
- public static final String GOOD_SELECTION_COLOUR = "#38C25B";
- // FBFFB8
- public static final String NEUTRAL_SELECTION_COLOUR = "#EDEB72";
- // FF9C9C
- public static final String BAD_SELECTION_COLOUR = "#F53D3D";
+ public static final String GOOD_SELECTION_COLOUR = "#38C25B";
+ public static final String NEUTRAL_SELECTION_COLOUR = "#FFEF73";
+ public static final String BAD_SELECTION_COLOUR = "#FF5C5C";
+
+ public static final String INVALID_PARAMETER_STYLE = "-fx-border-color: C9C9C9; -fx-border-radius: 2; -fx-padding: 0; -fx-background-color: " + BAD_SELECTION_COLOUR;
+ public static final String WARNING_PARAMETER_STYLE = "-fx-border-color: C9C9C9; -fx-border-radius: 2; -fx-padding: 0; -fx-background-color: " + NEUTRAL_SELECTION_COLOUR;
+ public static final String VALID_PARAMETER_STYLE = "-fx-border-color: C9C9C9; -fx-border-radius: 2; -fx-padding: 0; -fx-background-color: " + NEUTRAL_COLOUR;
/* Sizes and distances */
public static final double RESIZE_MARGIN = 5.0;
@@ -71,7 +71,7 @@ public class GUI extends Application {
public static void main(String[] args) {
cgp = new JCGP();
- resources = cgp.getResources();
+ resources = cgp.getResources();
launch();
}
@@ -166,17 +166,20 @@ public class GUI extends Application {
public void disableChromosomePanes(boolean value) {
chromosomeTabs.setDisable(value);
}
+
+ public void disable(boolean value) {
+ chromosomeTabs.setDisable(value);
+ settings.disableSettings(value);
+ }
public void playPause() {
if (!evolving) {
- settings.disableSettings(true);
- disableChromosomePanes(true);
+ disable(true);
unlockOutputs();
evolving = true;
cgpService.restart();
} else {
- settings.disableSettings(false);
- disableChromosomePanes(false);
+ disable(false);
updateNodeGrids();
evolving = false;
cgpService.cancel();
@@ -201,11 +204,8 @@ public class GUI extends Application {
}
}
- public void resetCGP() {
- cgp.remakePopulation();
+ public void reset() {
+ cgp.reset();
makeChromosomeTabPane();
-
- resources.set("currentGen", 1);
- resources.set("currentRun", 1);
}
}
diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java
index 61011aa..41b1bba 100644
--- a/src/jcgp/gui/settings/SettingsPane.java
+++ b/src/jcgp/gui/settings/SettingsPane.java
@@ -1,9 +1,6 @@
package jcgp.gui.settings;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
@@ -37,11 +34,15 @@ public class SettingsPane extends AnchorPane {
private VBox bpPane, eaPane, mutatorPane, ffPane, nfPane;
private ArrayList<GUIParameter> parameters = new ArrayList<GUIParameter>();
+ private GUI gui;
+
private boolean dragging = false;
public SettingsPane(JCGP cgp, GUI gui) {
super();
+ this.gui = gui;
+
setResizeListeners();
mainContainer = new VBox(8);
@@ -84,8 +85,7 @@ public class SettingsPane extends AnchorPane {
bpPane.getChildren().add(header);
- GUIParameter rows = GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("rows"));
- parameters.add(rows);
+ 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")));
@@ -98,14 +98,13 @@ public class SettingsPane extends AnchorPane {
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("maxFitness")));
parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("seed")));
parameters.add(GUIParameter.create((IntegerParameter) cgp.getResources().getParameter("report")));
bpPane.getChildren().addAll(parameters);
mainContainer.getChildren().add(bpPane);
-
-
}
private void initialiseEAParameters(final JCGP cgp) {
@@ -122,8 +121,9 @@ public class SettingsPane extends AnchorPane {
final VBox eaParameters = new VBox();
eaParameters.setSpacing(2);
+
if (cgp.getEvolutionaryAlgorithm().getLocalParameters() != null) {
- refreshParameters(cgp.getEvolutionaryAlgorithm().getLocalParameters().entrySet().iterator(), eaParameters);
+ refreshParameters(cgp.getEvolutionaryAlgorithm().getLocalParameters(), eaParameters);
}
eaCBox.setOnAction(new EventHandler<ActionEvent>() {
@@ -131,7 +131,7 @@ public class SettingsPane extends AnchorPane {
public void handle(ActionEvent event) {
cgp.setEvolutionaryAlgorithm(eaCBox.getSelectionModel().getSelectedIndex());
if (eaCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) {
- refreshParameters(eaCBox.getSelectionModel().getSelectedItem().getLocalParameters().entrySet().iterator(), eaParameters);
+ refreshParameters(eaCBox.getSelectionModel().getSelectedItem().getLocalParameters(), eaParameters);
}
}
});
@@ -156,7 +156,7 @@ public class SettingsPane extends AnchorPane {
final VBox mutatorParameters = new VBox();
mutatorParameters.setSpacing(2);
if (cgp.getEvolutionaryAlgorithm().getLocalParameters() != null) {
- refreshParameters(cgp.getMutator().getLocalParameters().entrySet().iterator(), mutatorParameters);
+ refreshParameters(cgp.getMutator().getLocalParameters(), mutatorParameters);
}
mutatorCBox.setOnAction(new EventHandler<ActionEvent>() {
@@ -164,7 +164,7 @@ public class SettingsPane extends AnchorPane {
public void handle(ActionEvent event) {
cgp.setEvolutionaryAlgorithm(mutatorCBox.getSelectionModel().getSelectedIndex());
if (mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) {
- refreshParameters(mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters().entrySet().iterator(), mutatorParameters);
+ refreshParameters(mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters(), mutatorParameters);
}
}
});
@@ -188,7 +188,7 @@ public class SettingsPane extends AnchorPane {
final VBox ffParameters = new VBox();
ffParameters.setSpacing(2);
if (cgp.getFitnessFunction().getLocalParameters() != null) {
- refreshParameters(cgp.getFitnessFunction().getLocalParameters().entrySet().iterator(), ffParameters);
+ refreshParameters(cgp.getFitnessFunction().getLocalParameters(), ffParameters);
}
ffCBox.setOnAction(new EventHandler<ActionEvent>() {
@@ -196,7 +196,7 @@ public class SettingsPane extends AnchorPane {
public void handle(ActionEvent event) {
cgp.setEvolutionaryAlgorithm(ffCBox.getSelectionModel().getSelectedIndex());
if (ffCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) {
- refreshParameters(ffCBox.getSelectionModel().getSelectedItem().getLocalParameters().entrySet().iterator(), ffParameters);
+ refreshParameters(ffCBox.getSelectionModel().getSelectedItem().getLocalParameters(), ffParameters);
}
}
});
@@ -244,8 +244,8 @@ public class SettingsPane extends AnchorPane {
@Override
public void handle(ActionEvent event) {
if (play.getText() == "Run") {
- if (applyChanges()) {
- gui.resetCGP();
+ if (isResetRequired()) {
+ resetExperiment();
}
play.setText("Pause");
} else {
@@ -260,8 +260,8 @@ public class SettingsPane extends AnchorPane {
step.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
- if (applyChanges()) {
- gui.resetCGP();
+ if (isResetRequired()) {
+ resetExperiment();
}
gui.step();
}
@@ -284,16 +284,15 @@ public class SettingsPane extends AnchorPane {
* @param cgp
* @param vb
*/
- private void refreshParameters(Iterator<Entry<String, Parameter>> it, VBox vb) {
+ private void refreshParameters(Parameter[] newParameters, VBox vb) {
parameters.removeAll(vb.getChildren());
vb.getChildren().clear();
- while (it.hasNext()) {
- Parameter parameter = ((Map.Entry<String, Parameter>) it.next()).getValue();
- GUIParameter gp = GUIParameter.create(parameter);
+ for (int i = 0; i < newParameters.length; i++) {
+ GUIParameter gp = GUIParameter.create(newParameters[i]);
parameters.add(gp);
vb.getChildren().add(gp);
- }
+ }
}
private void refreshFunctions(final FunctionSet fs, VBox vb) {
@@ -378,15 +377,22 @@ public class SettingsPane extends AnchorPane {
*
* @return true if the experiment needs to be reset, false otherwise.
*/
- private boolean applyChanges() {
+ private boolean isResetRequired() {
boolean reset = false;
-
for (GUIParameter parameter : parameters) {
- reset |= parameter.applyChange();
+ reset |= parameter.requiresReset();
}
-
+ System.out.println("reset: " + reset);
return reset;
}
+ private void resetExperiment() {
+ for (GUIParameter parameter : parameters) {
+ parameter.applyValue();
+ }
+ gui.reset();
+
+ }
+
}
diff --git a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java
index 8acd6dd..da564f7 100644
--- a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java
+++ b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java
@@ -1,46 +1,71 @@
package jcgp.gui.settings.parameters;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
import javafx.scene.control.CheckBox;
import jcgp.backend.parameters.BooleanParameter;
+import jcgp.backend.parameters.ParameterStatus;
+import jcgp.gui.GUI;
public class GUIBooleanParameter extends GUIParameter {
- GUIBooleanParameter(BooleanParameter parameter) {
+ private boolean originalValue;
+
+ GUIBooleanParameter(final BooleanParameter parameter) {
super();
this.parameter = parameter;
- value = new CheckBox(parameter.getName());
- ((CheckBox) value).setSelected(parameter.get());
+ originalValue = parameter.get();
+
+ valueControl = new CheckBox(parameter.getName());
+ ((CheckBox) valueControl).setSelected(parameter.get());
- value.setDisable(parameter.isMonitor());
+ valueControl.setDisable(parameter.isMonitor());
if (parameter.isMonitor()) {
makeLightBinding();
- System.out.println("light binding made for " + name);
+ } else {
+ ((CheckBox) valueControl).selectedProperty().addListener(new ChangeListener<Boolean>() {
+ @Override
+ public void changed(
+ ObservableValue<? extends Boolean> 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);
+ }
+ }
+ });
}
- getChildren().add(value);
+ getChildren().add(valueControl);
}
@Override
public void refreshValue() {
- if (!((CheckBox) value).selectedProperty().isBound()) {
- ((CheckBox) value).setSelected(((BooleanParameter) parameter).get());
+ if (!((CheckBox) valueControl).selectedProperty().isBound()) {
+ ((CheckBox) valueControl).setSelected(((BooleanParameter) parameter).get());
}
-
}
-
+
@Override
- public boolean applyChange() {
- if (((CheckBox) value).isSelected() != ((BooleanParameter) parameter).get() && (!parameter.isMonitor())) {
- // apply value
- ((BooleanParameter) parameter).set(((CheckBox) value).isSelected());
- if (parameter.isCritical()) {
- return true;
- }
- }
- return false;
+ public boolean requiresReset() {
+ return parameter.isCritical() && ((BooleanParameter) parameter).get() != originalValue;
+ }
+
+ @Override
+ public void applyValue() {
+ originalValue = ((BooleanParameter) parameter).get();
}
}
diff --git a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java
index 4b74c6e..a1b4526 100644
--- a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java
+++ b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java
@@ -1,51 +1,104 @@
package jcgp.gui.settings.parameters;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.TextField;
+import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Priority;
import javafx.scene.text.Text;
import jcgp.backend.parameters.DoubleParameter;
+import jcgp.backend.parameters.ParameterStatus;
import jcgp.gui.GUI;
public class GUIDoubleParameter extends GUIParameter {
- GUIDoubleParameter(DoubleParameter parameter) {
+ private double originalValue;
+
+ GUIDoubleParameter(final DoubleParameter parameter) {
super();
this.parameter = parameter;
+ originalValue = parameter.get();
+
name = new Text(parameter.getName());
- value = new TextField(String.valueOf(parameter.get()));
+ valueControl = new TextField(String.valueOf(parameter.get()));
+ valueControl.setStyle(GUI.VALID_PARAMETER_STYLE);
- ((TextField) value).setAlignment(Pos.CENTER_RIGHT);
+ ((TextField) valueControl).setAlignment(Pos.CENTER_RIGHT);
- setHgrow(value, Priority.ALWAYS);
+ setHgrow(valueControl, Priority.ALWAYS);
name.setWrappingWidth(GUI.WRAP_WIDTH);
- ((TextField) value).setEditable(!parameter.isMonitor());
+ ((TextField) valueControl).setEditable(!parameter.isMonitor());
+ // bind if monitor, else set changelistener
if (parameter.isMonitor()) {
makeLightBinding();
+ } else {
+ valueControl.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
+ public void handle( KeyEvent t ) {
+ char ch = t.getCharacter().toCharArray()[t.getCharacter().toCharArray().length - 1];
+ if (!((ch >= '0' && ch <= '9') || (ch == '.' && !((TextField) valueControl).getText().contains(".")))) {
+ t.consume();
+ }
+ }
+ });
+ ((TextField) valueControl).textProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(
+ ObservableValue<? extends String> observable,
+ 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);
+ }
+ }
+
+ }
+ });
+ valueControl.focusedProperty().addListener(new ChangeListener<Boolean>() {
+ @Override
+ public void changed(
+ ObservableValue<? extends Boolean> observable,
+ Boolean oldValue, Boolean newValue) {
+ if (!newValue && ((TextField) valueControl).getText().isEmpty()) {
+ ((TextField) valueControl).setText(String.valueOf(parameter.get()));
+ }
+ }
+ });
}
- getChildren().addAll(name, value);
+
+ getChildren().addAll(name, valueControl);
}
@Override
public void refreshValue() {
- ((TextField) value).setText(String.valueOf(((DoubleParameter) parameter).get()));
+ ((TextField) valueControl).setText(String.valueOf(((DoubleParameter) parameter).get()));
}
-
+
@Override
- public boolean applyChange() {
- if (Double.valueOf(((TextField) value).getText()) != ((DoubleParameter) parameter).get() && (!parameter.isMonitor())) {
- // apply value
- ((DoubleParameter) parameter).set(Double.valueOf(((TextField) value).getText()));
- if (parameter.isCritical()) {
- return true;
- }
- }
- return false;
- }
+ public boolean requiresReset() {
+ return parameter.isCritical() && ((DoubleParameter) parameter).get() != originalValue;
+ }
+
+ @Override
+ public void applyValue() {
+ originalValue = ((DoubleParameter) parameter).get();
+ }
+
}
diff --git a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java
index 70b78a6..bf1a61e 100644
--- a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java
+++ b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java
@@ -1,49 +1,103 @@
package jcgp.gui.settings.parameters;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.TextField;
+import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Priority;
import javafx.scene.text.Text;
import jcgp.backend.parameters.IntegerParameter;
+import jcgp.backend.parameters.ParameterStatus;
import jcgp.gui.GUI;
public class GUIIntegerParameter extends GUIParameter {
- GUIIntegerParameter(IntegerParameter parameter) {
+ private int originalValue;
+
+ GUIIntegerParameter(final IntegerParameter parameter) {
super();
this.parameter = parameter;
+ originalValue = parameter.get();
+
name = new Text(parameter.getName());
- value = new TextField(String.valueOf(parameter.get()));
+ valueControl = new TextField(String.valueOf(parameter.get()));
+ valueControl.setStyle(GUI.VALID_PARAMETER_STYLE);
- ((TextField) value).setAlignment(Pos.CENTER_RIGHT);
+ ((TextField) valueControl).setAlignment(Pos.CENTER_RIGHT);
- setHgrow(value, Priority.ALWAYS);
+ setHgrow(valueControl, Priority.ALWAYS);
name.setWrappingWidth(GUI.WRAP_WIDTH);
- ((TextField) value).setEditable(!parameter.isMonitor());
-
+ ((TextField) valueControl).setEditable(!parameter.isMonitor());
+
+ // bind if monitor, else set listeners
if (parameter.isMonitor()) {
makeLightBinding();
+ } else {
+ valueControl.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
+ public void handle( KeyEvent t ) {
+ char ch = t.getCharacter().toCharArray()[t.getCharacter().toCharArray().length - 1];
+ if (!(ch >= '0' && ch <= '9')) {
+ t.consume();
+ }
+ }
+ });
+ ((TextField) valueControl).textProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(
+ ObservableValue<? extends String> observable,
+ 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);
+ }
+ }
+
+ }
+ });
+ valueControl.focusedProperty().addListener(new ChangeListener<Boolean>() {
+ @Override
+ public void changed(
+ ObservableValue<? extends Boolean> observable,
+ Boolean oldValue, Boolean newValue) {
+ if (!newValue && ((TextField) valueControl).getText().isEmpty()) {
+ ((TextField) valueControl).setText(String.valueOf(parameter.get()));
+ }
+ }
+ });
}
- getChildren().addAll(name, value);
+ getChildren().addAll(name, valueControl);
}
@Override
public void refreshValue() {
- ((TextField) value).setText(String.valueOf(((IntegerParameter) parameter).get()));
+ ((TextField) valueControl).setText(String.valueOf(((IntegerParameter) parameter).get()));
}
@Override
- public boolean applyChange() {
- if (Integer.valueOf(((TextField) value).getText()) != ((IntegerParameter) parameter).get() && (!parameter.isMonitor())) {
- // apply value
- ((IntegerParameter) parameter).set(Integer.valueOf(((TextField) value).getText()));
- return parameter.isCritical();
- }
- return false;
+ public boolean requiresReset() {
+ return parameter.isCritical() && ((IntegerParameter) parameter).get() != originalValue;
+ }
+
+ @Override
+ public void applyValue() {
+ originalValue = ((IntegerParameter) parameter).get();
}
+
}
diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java
index a783d71..9d6f07a 100644
--- a/src/jcgp/gui/settings/parameters/GUIParameter.java
+++ b/src/jcgp/gui/settings/parameters/GUIParameter.java
@@ -7,6 +7,7 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.control.Control;
+import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import jcgp.backend.parameters.BooleanParameter;
@@ -18,13 +19,19 @@ public abstract class GUIParameter extends HBox {
protected Parameter parameter;
protected Text name;
- protected Control value;
+ protected Control valueControl;
+
+ protected Tooltip tooltip;
protected AtomicBoolean updateCheck = new AtomicBoolean(true);
protected GUIParameter() {
setAlignment(Pos.CENTER_LEFT);
setSpacing(5);
+
+ tooltip = new Tooltip();
+ tooltip.setStyle("-fx-background-color: white; -fx-border-color: black; .page-corner {-fx-background-color: transparent;}");
+ tooltip.setSkin(null);
}
protected final void makeLightBinding() {
@@ -48,6 +55,10 @@ public abstract class GUIParameter extends HBox {
public abstract void refreshValue();
+ public abstract boolean requiresReset();
+
+ public abstract void applyValue();
+
public static GUIParameter create(Parameter parameter) {
if (parameter instanceof IntegerParameter) {
return new GUIIntegerParameter((IntegerParameter) parameter);
@@ -59,12 +70,4 @@ public abstract class GUIParameter extends HBox {
throw new ClassCastException("No GUIParameter subclass exists for argument of type " + parameter.getClass());
}
}
-
- /**
- * Writes the GUI parameter value back to the resources parameter,
- * if any changes were made.
- *
- * @return true if the experiment needs to be reset, false otherwise.
- */
- public abstract boolean applyChange();
}