diff options
Diffstat (limited to 'src')
21 files changed, 613 insertions, 237 deletions
| diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index 538f677..6d881d4 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -1,16 +1,13 @@  package jcgp; -import java.util.ArrayList; -  import jcgp.backend.modules.es.EvolutionaryStrategy;  import jcgp.backend.modules.es.MuPlusLambda;  import jcgp.backend.modules.es.TournamentSelection; -import jcgp.backend.modules.fitness.DigitalCircuit; -import jcgp.backend.modules.fitness.Problem; -import jcgp.backend.modules.fitness.SymbolicRegression; -import jcgp.backend.modules.fitness.TestCaseProblem.TestCase;  import jcgp.backend.modules.mutator.Mutator;  import jcgp.backend.modules.mutator.PointMutator; +import jcgp.backend.modules.problem.DigitalCircuit; +import jcgp.backend.modules.problem.Problem; +import jcgp.backend.modules.problem.SymbolicRegression;  import jcgp.backend.population.Population;  import jcgp.backend.resources.Console;  import jcgp.backend.resources.ModifiableResources; @@ -72,16 +69,6 @@ public class JCGP {  		setProblem(0);  		population = new Population(resources); -		 -		ArrayList<TestCase<Integer>> tc = new ArrayList<TestCase<Integer>>(); -		tc.add(new TestCase<Integer>(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); -		 -		((SymbolicRegression) problem).setTestCases(tc); -		 -		ArrayList<TestCase<Integer>> tcdc = new ArrayList<TestCase<Integer>>(); -		tcdc.add(new TestCase<Integer>(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); -		 -		((DigitalCircuit) problems[1]).setTestCases(tc);  	}  	public ModifiableResources getResources() { diff --git a/src/jcgp/backend/exceptions/ParameterMismatchException.java b/src/jcgp/backend/exceptions/ParameterMismatchException.java index 3ab9fa1..83e2ba2 100644 --- a/src/jcgp/backend/exceptions/ParameterMismatchException.java +++ b/src/jcgp/backend/exceptions/ParameterMismatchException.java @@ -6,5 +6,5 @@ public class ParameterMismatchException extends RuntimeException {  	 *   	 */  	private static final long serialVersionUID = -3161318886125868134L; - +	  } diff --git a/src/jcgp/backend/modules/fitness/DigitalCircuit.java b/src/jcgp/backend/modules/problem/DigitalCircuit.java index 8677d5f..d94197d 100644 --- a/src/jcgp/backend/modules/fitness/DigitalCircuit.java +++ b/src/jcgp/backend/modules/problem/DigitalCircuit.java @@ -1,4 +1,6 @@ -package jcgp.backend.modules.fitness; +package jcgp.backend.modules.problem; + +import java.util.ArrayList;  import jcgp.backend.function.BitwiseLogic;  import jcgp.backend.resources.Resources; @@ -8,6 +10,11 @@ public class DigitalCircuit extends TestCaseProblem<Integer> {  	public DigitalCircuit(Resources resources) {  		super(resources);  		functionSet = new BitwiseLogic(); +		 +		ArrayList<TestCase<Integer>> tc = new ArrayList<TestCase<Integer>>(); +		tc.add(new TestCase<Integer>(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); +		 +		setTestCases(tc);  	}  	@Override diff --git a/src/jcgp/backend/modules/fitness/Problem.java b/src/jcgp/backend/modules/problem/Problem.java index 1e70c13..d01f5b0 100644 --- a/src/jcgp/backend/modules/fitness/Problem.java +++ b/src/jcgp/backend/modules/problem/Problem.java @@ -1,4 +1,4 @@ -package jcgp.backend.modules.fitness; +package jcgp.backend.modules.problem;  import jcgp.backend.function.FunctionSet;  import jcgp.backend.modules.Module; diff --git a/src/jcgp/backend/modules/fitness/SymbolicRegression.java b/src/jcgp/backend/modules/problem/SymbolicRegression.java index cb9d1a7..c92d183 100644 --- a/src/jcgp/backend/modules/fitness/SymbolicRegression.java +++ b/src/jcgp/backend/modules/problem/SymbolicRegression.java @@ -1,4 +1,6 @@ -package jcgp.backend.modules.fitness; +package jcgp.backend.modules.problem; + +import java.util.ArrayList;  import jcgp.backend.function.IntegerArithmetic;  import jcgp.backend.resources.Resources; @@ -8,6 +10,12 @@ public class SymbolicRegression extends TestCaseProblem<Integer> {  	public SymbolicRegression(Resources resources) {  		super(resources);  		functionSet = new IntegerArithmetic(); +		 +		ArrayList<TestCase<Integer>> tc = new ArrayList<TestCase<Integer>>(); +		tc.add(new TestCase<Integer>(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); +		tc.add(new TestCase<Integer>(new Integer[]{3, 2, 5}, new Integer[]{2, 5, 9})); +		 +		setTestCases(tc);  	}  	@Override diff --git a/src/jcgp/backend/modules/fitness/TestCaseProblem.java b/src/jcgp/backend/modules/problem/TestCaseProblem.java index 7dd24af..68318cf 100644 --- a/src/jcgp/backend/modules/fitness/TestCaseProblem.java +++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java @@ -1,8 +1,9 @@ -package jcgp.backend.modules.fitness; +package jcgp.backend.modules.problem; -import java.util.ArrayList;  import java.util.List; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Population;  import jcgp.backend.resources.Resources; @@ -19,10 +20,9 @@ import jcgp.backend.resources.parameters.Parameter;   * @author Eduardo Pedroni   *   */ -public abstract class TestCaseProblem<U> extends Problem { +public abstract class TestCaseProblem<U extends Object> extends Problem {  	public static class TestCase<T> { -  		private T[] inputs;  		private T[] outputs; @@ -48,19 +48,26 @@ public abstract class TestCaseProblem<U> extends Problem {  		}  	} -	private ArrayList<TestCase<U>> testCases; +	private ObservableList<TestCase<U>> testCases;  	private IntegerParameter maxFitness; +	private final int inputCount, outputCount; +	 +	private U type;  	public TestCaseProblem(Resources resources) {  		super(); +		inputCount = resources.inputs(); +		outputCount = resources.outputs(); +		  		maxFitness = new IntegerParameter(0, "Max fitness", true, false) {  			@Override  			public void validate(Number newValue) {  				// blank  			}  		}; -		testCases = new ArrayList<TestCase<U>>(); +		testCases = FXCollections.observableArrayList(); +		//testCases = new ObservableList<TestCase<U>>();  	} @@ -90,6 +97,11 @@ public abstract class TestCaseProblem<U> extends Problem {  		return new Parameter[]{maxFitness};  	} +	@Override +	public boolean isPerfectSolution(Chromosome fittest) { +		return fittest.getFitness() >= maxFitness.get(); +	} +	  	private int getMaxFitness() {  		int fitness = 0; @@ -106,9 +118,39 @@ public abstract class TestCaseProblem<U> extends Problem {  		maxFitness.set(getMaxFitness());  	} -	@Override -	public boolean isPerfectSolution(Chromosome fittest) { -		return fittest.getFitness() >= maxFitness.get(); +	public ObservableList<TestCase<U>> getTestCases() { +		return testCases; +	} +	 +	public void addTestCase(TestCase<U> testCase) { +		if (testCase.getInputs().length != inputCount) { +			throw new IllegalArgumentException("Received test case with " + testCase.getInputs().length +  +					"inputs but need exactly " + inputCount); +		} else if (testCase.getOutputs().length != outputCount) { +			throw new IllegalArgumentException("Received test case with " + testCase.getOutputs().length +  +					"outputs but need exactly " + outputCount); +		} else { +			this.testCases.add(testCase); +			maxFitness.set(getMaxFitness()); +		} +	} +	 +	public void removeTestCase(TestCase<U> testCase) { +		testCases.remove(testCase); +		maxFitness.set(getMaxFitness()); +	} +	 +	public int getInputCount() { +		return inputCount; +	} +	 +	public int getOutputCount() { +		return outputCount; +	} +	 +	public Class<?> getType() { +		return type.getClass();  	}  } + diff --git a/src/jcgp/gui/GUI.java b/src/jcgp/gui/GUI.java index 5a7a16d..6d87de1 100644 --- a/src/jcgp/gui/GUI.java +++ b/src/jcgp/gui/GUI.java @@ -4,24 +4,26 @@ import javafx.application.Application;  import javafx.application.Platform;  import javafx.concurrent.Service;  import javafx.concurrent.Task; +import javafx.event.EventHandler;  import javafx.scene.Scene; +import javafx.scene.input.MouseEvent;  import javafx.scene.layout.BorderPane;  import javafx.scene.layout.Pane;  import javafx.stage.Stage; +import javafx.stage.WindowEvent;  import jcgp.JCGP; -import jcgp.backend.resources.Resources; +import jcgp.backend.modules.problem.TestCaseProblem.TestCase;  import jcgp.gui.console.GUIConsole;  import jcgp.gui.dragresize.HorizontalDragResize;  import jcgp.gui.dragresize.VerticalDragResize;  import jcgp.gui.population.FunctionSelector; +import jcgp.gui.population.GUINode;  import jcgp.gui.population.PopulationPane;  import jcgp.gui.settings.SettingsPane;  public class GUI extends Application {  	/* Colours */ -	/** NEUTRAL_COLOUR is the colour elements should be when no interaction is occurring -	 * (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";  	public static final String MEDIUM_HIGHLIGHT_COLOUR = "#75BAFF"; @@ -33,16 +35,12 @@ public class GUI extends Application {  	/* Sizes and distances */      public static final double RESIZE_MARGIN = 5.0; +    public static final double SETTINGS_MIN_WIDTH = 200; +    public static final double CONSOLE_MIN_HEIGHT = 100; -    public static final double SETTINGS_WIDTH = 200; -    public static final double CONSOLE_HEIGHT = 100; -     -    public static final double WRAP_WIDTH = 90; -     -	public static final JCGP jcgp = new JCGP(); -	public static final Resources resources = jcgp.getResources(); +	private final JCGP jcgp; -	public static final FunctionSelector functionSelector = new FunctionSelector(resources.getFunctionSet()); +	private final FunctionSelector functionSelector;  	private PopulationPane populationPane; @@ -50,53 +48,62 @@ public class GUI extends Application {  	private SettingsPane settingsPane; -	private static boolean working = false; -	 -	private Object printLock = new Object(); -	 -	private Service<Void> cgpService = new Service<Void> () { -		@Override -		protected Task<Void> createTask() { -			Task<Void> t = new Task<Void>() { -				@Override -				protected Void call() throws Exception { -					while (!isCancelled() && !jcgp.isFinished()) { -						synchronized (printLock) { -							Platform.runLater(consoleFlush); -							jcgp.nextGeneration(); -							printLock.wait(); -						} -					} -					if (jcgp.isFinished()) { -						Platform.runLater(new Runnable() { -							@Override -							public void run() { -								runningMode(false); -							} -						}); -					} -					return null; -				} -			}; -			return t; -		} -	}; -	 -	private Runnable consoleFlush = new Runnable() { -		@Override -		public void run() { -			synchronized(printLock) { -				console.flush(); -				printLock.notifyAll(); -			} -		} -	}; +	private boolean running = false; +	 +	private final Object printLock = new Object(); +	 +	private Service<Void> cgpService; +	 +	private Runnable consoleFlush;  	public static void main(String[] args) { -		 +		new GUI();  		launch();  	} +	public GUI() { +		jcgp = new JCGP(); +		functionSelector = new FunctionSelector(jcgp.getResources().getFunctionSet()); +		 +		consoleFlush = new Runnable() { +			@Override +			public void run() { +				synchronized(printLock) { +					console.flush(); +					printLock.notifyAll(); +				} +			} +		}; +		 +		cgpService = new Service<Void> () { +			@Override +			protected Task<Void> createTask() { +				Task<Void> t = new Task<Void>() { +					@Override +					protected Void call() throws Exception { +						while (!isCancelled() && !jcgp.isFinished()) { +							synchronized (printLock) { +								Platform.runLater(consoleFlush); +								jcgp.nextGeneration(); +								printLock.wait(); +							} +						} +						if (jcgp.isFinished()) { +							Platform.runLater(new Runnable() { +								@Override +								public void run() { +									runningMode(false); +								} +							}); +						} +						return null; +					} +				}; +				return t; +			} +		}; +	} +	  	@Override  	public void start(Stage primaryStage) throws Exception {  		console = new GUIConsole(); @@ -109,9 +116,9 @@ public class GUI extends Application {  		 */  		BorderPane leftFrame = new BorderPane(); -		populationPane = new PopulationPane(jcgp); +		populationPane = new PopulationPane(this); -		settingsPane = new SettingsPane(jcgp, this); +		settingsPane = new SettingsPane(this);  		HorizontalDragResize.makeDragResizable(settingsPane);  		VerticalDragResize.makeDragResizable(console); @@ -135,11 +142,18 @@ public class GUI extends Application {  		primaryStage.setMinWidth(800);  		primaryStage.setMinHeight(600);  		primaryStage.show(); +		 +		primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { +			@Override +			public void handle(WindowEvent event) { +				settingsPane.getTestCaseTable().close(); +			} +		});  	}  	public void runPause() {  		if (!jcgp.isFinished() && settingsPane.areParametersValid()) { -			if (!working) { +			if (!running) {  				runningMode(true);  				cgpService.restart();  			} else { @@ -150,7 +164,7 @@ public class GUI extends Application {  	}  	public void step() { -		if (!working && !jcgp.isFinished() && settingsPane.areParametersValid()) { +		if (!running && !jcgp.isFinished() && settingsPane.areParametersValid()) {  			if (settingsPane.isResetRequired()) {  				reset();  			} @@ -166,20 +180,18 @@ public class GUI extends Application {  	}  	public void reset() { -		if (!working && settingsPane.areParametersValid()) { +		if (!running && settingsPane.areParametersValid()) {  			settingsPane.applyParameters();  			jcgp.reset(); -			populationPane.remakeTabs(jcgp.getPopulation(), jcgp.getResources()); +			populationPane.remakeTabs();  			settingsPane.revalidateParameters(); +			System.out.println("[reset] call: " + jcgp.isFinished());  			settingsPane.updateControls(false, jcgp.isFinished());  			console.flush();  		}  	} -	private void runningMode(boolean value) { -		populationPane.setDisable(value); -		settingsPane.updateControls(value, jcgp.isFinished()); -		 +	private void runningMode(boolean value) {		  		if (value) {  			populationPane.unlockOutputs();  			if (settingsPane.isResetRequired()) { @@ -190,14 +202,33 @@ public class GUI extends Application {  			populationPane.relockOutputs();  			settingsPane.revalidateParameters();  		} -		working = value; +		populationPane.setDisable(value); +		settingsPane.updateControls(value, jcgp.isFinished()); +		 +		running = value;  	} -	public static void updateFunctionSelector() { -		functionSelector.remakeFunctions(resources.getFunctionSet()); +	public void updateFunctionSelector() { +		functionSelector.remakeFunctions(jcgp.getResources().getFunctionSet()); +	} +	 +	public boolean isWorking() { +		return running; +	} + +	public void bringFunctionSelector(MouseEvent event, GUINode node) { +		functionSelector.relocateAndShow(event, node); +	} + +	public JCGP getExperiment() { +		return jcgp;  	} -	public static boolean isWorking() { -		return working; +	public void evaluateTestCase(TestCase<Object> testCase) { +		populationPane.evaluateTestCase(testCase); +	} + +	public void hideGeneValues() { +		populationPane.hideValues();  	}  } diff --git a/src/jcgp/gui/console/GUIConsole.java b/src/jcgp/gui/console/GUIConsole.java index 8148ec8..e77e222 100644 --- a/src/jcgp/gui/console/GUIConsole.java +++ b/src/jcgp/gui/console/GUIConsole.java @@ -82,8 +82,8 @@ public class GUIConsole extends AnchorPane implements Console {  		AnchorPane.setRightAnchor(textArea, 0.0);  		AnchorPane.setLeftAnchor(textArea, 0.0); -		setMinHeight(GUI.CONSOLE_HEIGHT); -		setPrefHeight(GUI.CONSOLE_HEIGHT); +		setMinHeight(GUI.CONSOLE_MIN_HEIGHT); +		setPrefHeight(GUI.CONSOLE_MIN_HEIGHT);  		getChildren().add(textArea);  	} diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java index 1f67255..0279d09 100644 --- a/src/jcgp/gui/population/ChromosomePane.java +++ b/src/jcgp/gui/population/ChromosomePane.java @@ -10,7 +10,7 @@ import jcgp.backend.population.Connection;  import jcgp.backend.population.Input;  import jcgp.backend.population.Node;  import jcgp.backend.resources.Resources; - +import jcgp.gui.GUI;  public class ChromosomePane extends ScrollPane { @@ -21,15 +21,23 @@ public class ChromosomePane extends ScrollPane {  	private Pane content;  	private ArrayList<Line> connectionLines; -	  	private ArrayList<GUIOutput> relock = new ArrayList<GUIOutput>(); -		 +	 +	private int rows, columns; +	  	private boolean target = false; +	private boolean evaluating = false; -	public ChromosomePane(Chromosome chromosome, Resources resources) { -		super();		 +	public ChromosomePane(Chromosome chromosome, GUI gui) { +		super(); +		 +		final Resources resources = gui.getExperiment().getResources(); +		 +		rows = resources.rows(); +		columns = resources.columns(); +		  		connectionLines = new ArrayList<Line>(); -				 +		  		content = new Pane();  		content.setId("content pane for genes"); @@ -42,10 +50,10 @@ public class ChromosomePane extends ScrollPane {  			content.getChildren().addAll(guiInputs[i]);  		}  		// nodes -		guiNodes = new GUINode[resources.rows()][resources.columns()]; +		guiNodes = new GUINode[rows][columns];  		double angle, xPos, yPos; -		for (int r = 0; r < guiNodes.length; r++) { -			for (int c = 0; c < guiNodes[r].length; c++) { +		for (int r = 0; r < rows; r++) { +			for (int c = 0; c < columns; c++) {  				// make the connection lines  				Line lines[] = new Line[resources.arity()];  				for (int l = 0; l < lines.length; l++) { @@ -59,7 +67,7 @@ public class ChromosomePane extends ScrollPane {  					connectionLines.add(lines[l]);  				}  				// make the GUI elements -				guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), lines); +				guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), lines, gui);  			}  			content.getChildren().addAll(guiNodes[r]);  		} @@ -74,7 +82,7 @@ public class ChromosomePane extends ScrollPane {  			line.setVisible(false);  			connectionLines.add(line);  			// make the GUI elements -			guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), line); +			guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), line, gui);  			content.getChildren().addAll(guiOutputs[i]);  		} @@ -83,7 +91,7 @@ public class ChromosomePane extends ScrollPane {  		setContent(content);  	} -	public GUIGene getGuiGene(Connection gene) { +	protected GUIGene getGuiGene(Connection gene) {  		if (gene instanceof Input) {  			return guiInputs[((Input) gene).getIndex()];  		} else if (gene instanceof Node) { @@ -94,24 +102,28 @@ public class ChromosomePane extends ScrollPane {  		}	  	} -	public boolean isTarget() { +	protected boolean isTarget() {  		return target;  	} -	public void setTarget(boolean newValue) { +	protected void setTarget(boolean newValue) {  		target = newValue;  	}  	public void updateGenes() { -		for (int r = 0; r < guiNodes.length; r++) { -			for (int c = 0; c < guiNodes[r].length; c++) { +		for (int r = 0; r < rows; r++) { +			for (int c = 0; c < columns; c++) {  				guiNodes[r][c].updateLines(); -				guiNodes[r][c].updateFunction(); +				guiNodes[r][c].updateText();  			}  		}  		for (int i = 0; i < guiOutputs.length; i++) {  			guiOutputs[i].updateLines();  		} +		if (isEvaluating()) { +			evaluate(0); +		} +		  	}  	public void unlockOutputs() { @@ -129,4 +141,50 @@ public class ChromosomePane extends ScrollPane {  			relock.get(i).lock();  		}  	} +	 +	public void setInputs(Object[] values) { +		evaluating = true; +		for (int i = 0; i < guiInputs.length; i++) { +			guiInputs[i].setValue(values[i]); +			guiInputs[i].updateText(); +		} +		evaluate(0); +	} + +	public void evaluate(int start) { +		if (start >= 0 || start < columns) { +			for (int c = start; c < columns; c++) { +				for (int r = 0; r < rows; r++) { +					guiNodes[r][c].calculate(); +					guiNodes[r][c].updateText(); +				} +			} +			for (int o = 0; o < guiOutputs.length; o++) { +				guiOutputs[o].calculate(); +				guiOutputs[o].updateText(); +			} +		} +	} +	 +	public void hideValues() { +		evaluating = false; +		for (int i = 0; i < guiInputs.length; i++) { +			guiInputs[i].updateText(); +		} +		for (int c = 0; c < columns; c++) { +			for (int r = 0; r < rows; r++) { +				guiNodes[r][c].updateText(); +			} +		} +		for (int o = 0; o < guiOutputs.length; o++) { +			guiOutputs[o].updateText(); +		} +	} + +	/** +	 * @return the evaluating +	 */ +	public boolean isEvaluating() { +		return evaluating; +	}  } diff --git a/src/jcgp/gui/population/FunctionSelector.java b/src/jcgp/gui/population/FunctionSelector.java index 0a9606f..28eb54d 100644 --- a/src/jcgp/gui/population/FunctionSelector.java +++ b/src/jcgp/gui/population/FunctionSelector.java @@ -50,8 +50,7 @@ public class FunctionSelector extends VBox {  			l.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {  				@Override  				public void handle(MouseEvent event) { -					target.getGene().setFunction(fs.getAllowedFunction(index)); -					target.updateFunction(); +					target.setFunction(fs.getAllowedFunction(index));  					dismiss();  				}  			}); diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java index 6e9d098..5ce839e 100644 --- a/src/jcgp/gui/population/GUIGene.java +++ b/src/jcgp/gui/population/GUIGene.java @@ -10,18 +10,6 @@ import javafx.scene.text.TextAlignment;  import jcgp.backend.population.Connection;  import jcgp.backend.population.Gene; -enum GUIGeneState { -	NEUTRAL, -	HOVER, -	INDIRECT_HOVER, -	ACTIVE_HOVER, -	LOCKED_HOVER, -	SOURCE, -	TARGET, -	NO_CHANGE_TARGET, -	FORBIDDEN_TARGET -} -  public abstract class GUIGene extends Group {  	public static final double NODE_RADIUS = 30; @@ -32,6 +20,18 @@ public abstract class GUIGene extends Group {  	public static final double NODE_TEXT = NODE_RADIUS / 2.5; +	public enum GUIGeneState { +		NEUTRAL, +		HOVER, +		INDIRECT_HOVER, +		ACTIVE_HOVER, +		LOCKED_HOVER, +		SOURCE, +		TARGET, +		NO_CHANGE_TARGET, +		FORBIDDEN_TARGET +	} +	  	protected Text text = new Text();  	protected Circle mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); @@ -40,6 +40,8 @@ public abstract class GUIGene extends Group {  	protected ChromosomePane parent;  	protected int locked = 0; +	 +	protected Object value;  	public GUIGene() {  		text.setFont(Font.font("Arial", 12)); @@ -73,7 +75,7 @@ public abstract class GUIGene extends Group {  	public abstract void addLocks(int value);  	/** -	 * test +	 *   	 *   	 * @param value  	 */ @@ -93,5 +95,9 @@ public abstract class GUIGene extends Group {  	public abstract void setConnectionLine(GUIGene gene); +	public Object getValue() { +		return value; +	} +	public abstract void updateText();  } diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java index b4eccaa..6a783db 100644 --- a/src/jcgp/gui/population/GUIInput.java +++ b/src/jcgp/gui/population/GUIInput.java @@ -23,8 +23,7 @@ public class GUIInput extends GUIGene {  		relocate(NODE_RADIUS,  				(input.getIndex() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS); -		text.setText("I: " + input.getIndex()); -		 +		updateText();  		Circle outputSocket = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white"));  		outputSocket.setId(String.valueOf(0)); @@ -232,5 +231,19 @@ public class GUIInput extends GUIGene {  	@Override  	public void setConnectionLine(GUIGene gene) {  		// nothing +	} + +	public void setValue(Object newValue) { +		value = newValue; +		input.setValue(newValue); +	} + +	@Override +	public void updateText() { +		if (parent.isEvaluating()) { +			text.setText("I: " + input.getIndex() + "\nValue: " + value.toString()); +		} else { +			text.setText("I: " + input.getIndex()); +		}  	}	  } diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index 8e2d8a0..2b953c0 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -7,24 +7,29 @@ import javafx.scene.input.MouseEvent;  import javafx.scene.paint.Paint;  import javafx.scene.shape.Circle;  import javafx.scene.shape.Line; +import jcgp.backend.function.Function;  import jcgp.backend.population.Connection;  import jcgp.backend.population.Input;  import jcgp.backend.population.Node; +import jcgp.backend.resources.Resources;  import jcgp.gui.GUI;  public class GUINode extends GUIGene {  	private Line[] lines;  	private Node node; +	private Resources resources;  	private int connectionIndex = 0; +	 -	public GUINode(ChromosomePane parentRef, final Node node, Line[] connectionLines) { +	public GUINode(ChromosomePane parentRef, final Node node, Line[] connectionLines, final GUI gui) {  		super();  		// store references  		this.parent = parentRef;  		this.node = node;  		this.lines = connectionLines; +		this.resources = gui.getExperiment().getResources();  		// move the GUIGene to the right position  		relocate(((node.getColumn() + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, @@ -40,12 +45,12 @@ public class GUINode extends GUIGene {  		Circle output = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white"));  		output.setStroke(Paint.valueOf("black")); -		text.setText(node.getFunction().getName()); +		updateText(); -		Circle[] sockets = new Circle[GUI.resources.arity()]; +		Circle[] sockets = new Circle[resources.arity()];  		double angle, xPos, yPos;  		for (int l = 0; l < sockets.length; l++) { -			angle = (((l + 1) / ((double) (GUI.resources.arity() + 1))) * THETA) - (THETA / 2); +			angle = (((l + 1) / ((double) (resources.arity() + 1))) * THETA) - (THETA / 2);  			xPos = -Math.cos(angle) * NODE_RADIUS;  			yPos = Math.sin(angle) * NODE_RADIUS; @@ -128,7 +133,7 @@ public class GUINode extends GUIGene {  		addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {  			@Override  			public void handle(MouseEvent event) { -				GUI.functionSelector.relocateAndShow(event, (GUINode) event.getSource()); +				gui.bringFunctionSelector(event, (GUINode) event.getSource());  			}  		}); @@ -189,17 +194,16 @@ public class GUINode extends GUIGene {  				// the user released the drag gesture on this node, react appropriately  				if (isAllowed((GUIGene) event.getGestureSource(), (GUIGene) event.getSource())) {  					if (source.isLocked()) { -						// remove locks from the old connection, add the to the new +						// remove locks from the old connection, add the to setConnethe new  						// note that the old connection may still have locks after this  						parent.getGuiGene(source.getChangingConnection()).removeLocks(source.getLocks()); -						source.setChangingConnection(node);  						addLocks(source.getLocks());  					} else {  						if (source instanceof GUIOutput) {  							source.resetState();  						} -						source.setChangingConnection(node);  					} +					source.setChangingConnection(node);  				}  				source.updateLines(); @@ -316,7 +320,7 @@ public class GUINode extends GUIGene {  			} else if (target instanceof GUINode) {  				// target and source are nodes, let's look at levels back  				Node t = ((GUINode) target).getGene(), s = ((GUINode) source).getGene(); -				if (s.getColumn() - t.getColumn() > 0 && s.getColumn() - t.getColumn() <= GUI.resources.levelsBack()) { +				if (s.getColumn() - t.getColumn() > 0 && s.getColumn() - t.getColumn() <= resources.levelsBack()) {  					return true;  				}  				return false; @@ -395,6 +399,9 @@ public class GUINode extends GUIGene {  	@Override  	public void setChangingConnection(Connection newConnection) {  		node.setConnection(connectionIndex, newConnection); +		if (parent.isEvaluating()) { +			parent.evaluate(node.getColumn()); +		}  	} @@ -445,7 +452,26 @@ public class GUINode extends GUIGene {  		lines[connectionIndex].setEndY(gene.getLayoutY());  	} -	public void updateFunction() { -		text.setText(node.getFunction().getName()); +	public void updateText() { +		if (parent.isEvaluating()) { +			text.setText(node.getFunction().getName() + "\nValue: " + value.toString()); +		} else { +			text.setText(node.getFunction().getName()); +		} +	} + +	public void calculate() { +		value = node.getValue(); +	} +	 +	public void setFunction(Function function) { +		node.setFunction(function); +		if (parent.isEvaluating()) { +			calculate(); +			parent.evaluate(node.getColumn()); +		} else { +			updateText(); +		} +		  	}  } diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java index c5b889e..89c12b3 100644 --- a/src/jcgp/gui/population/GUIOutput.java +++ b/src/jcgp/gui/population/GUIOutput.java @@ -16,23 +16,21 @@ import jcgp.gui.GUI;  public class GUIOutput extends GUIGene {  	private Line sourceLine; -  	private Output output; -	public GUIOutput(ChromosomePane parentRef, final Output output, Line line) { +	public GUIOutput(ChromosomePane parentRef, final Output output, Line line, GUI gui) {  		super();  		this.parent = parentRef;  		this.output = output;  		this.sourceLine = line; -		relocate(((GUI.resources.columns() + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, +		relocate(((gui.getExperiment().getResources().columns() + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS,  				(output.getIndex() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS);  		// set the line ends correctly  		updateLines(); - -		text.setText("O: " + output.getIndex()); +		updateText();  		Circle socket = new Circle(-NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white"));  		socket.setId(String.valueOf(0)); @@ -274,6 +272,10 @@ public class GUIOutput extends GUIGene {  	@Override  	public void setChangingConnection(Connection newConnection) {  		output.setConnection(0, newConnection);	 +		if (parent.isEvaluating()) { +			calculate(); +			updateText(); +		}  	}  	@Override @@ -311,5 +313,19 @@ public class GUIOutput extends GUIGene {  			setLocked(true);  		}  	} +	 +	public void calculate() { +		value = output.getSource().getValue(); +	} + +	@Override +	public void updateText() { +		if (parent.isEvaluating()) { +			text.setText("O: " + output.getIndex() + "\nValue: " + value.toString()); +		} else { +			text.setText("O: " + output.getIndex()); +		} +		 +	}  } diff --git a/src/jcgp/gui/population/PopulationPane.java b/src/jcgp/gui/population/PopulationPane.java index 5232eb5..64b61c4 100644 --- a/src/jcgp/gui/population/PopulationPane.java +++ b/src/jcgp/gui/population/PopulationPane.java @@ -3,26 +3,29 @@ package jcgp.gui.population;  import javafx.scene.control.Tab;  import javafx.scene.control.TabPane;  import jcgp.JCGP; -import jcgp.backend.population.Population; -import jcgp.backend.resources.Resources; +import jcgp.backend.modules.problem.TestCaseProblem; +import jcgp.backend.modules.problem.TestCaseProblem.TestCase; +import jcgp.gui.GUI;  public class PopulationPane extends TabPane { -	public PopulationPane(JCGP jcgp) { +	private GUI gui; +	 +	public PopulationPane(GUI gui) {  		super(); -		 +		this.gui = gui;  		setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); -		 -		remakeTabs(jcgp.getPopulation(), jcgp.getResources()); +		remakeTabs();  	} -	public void remakeTabs(Population population, Resources resources) { +	public void remakeTabs() {  		getTabs().clear(); +		JCGP jcgp = gui.getExperiment();  		Tab tab;  		ChromosomePane cp; -		for (int i = 0; i < resources.populationSize(); i++) { -			cp = new ChromosomePane(population.getChromosome(i), resources); +		for (int i = 0; i < jcgp.getResources().populationSize(); i++) { +			cp = new ChromosomePane(jcgp.getPopulation().getChromosome(i), gui);  			tab = new Tab("Chr " + i);  			tab.setContent(cp);  			getTabs().add(tab); @@ -46,4 +49,23 @@ public class PopulationPane extends TabPane {  			((ChromosomePane) getTabs().get(i).getContent()).relockOutputs();  		}  	} +	 +	public void evaluateTestCase(TestCase<Object> testCase) { +		if (gui.getExperiment().getProblem() instanceof TestCaseProblem) { +			if (testCase.getInputs().length == gui.getExperiment().getResources().inputs()) { +				for (int i = 0; i < getTabs().size(); i++) { +					((ChromosomePane) getTabs().get(i).getContent()).setInputs(testCase.getInputs()); +				} +			} else { +				throw new IllegalArgumentException("Test case has " + testCase.getInputs().length +						+ " inputs and chromosome has " + gui.getExperiment().getResources().inputs()); +			} +		} +	} +	 +	public void hideValues() { +		for (int i = 0; i < getTabs().size(); i++) { +			((ChromosomePane) getTabs().get(i).getContent()).hideValues(); +		} +	}  } diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java index e455846..9fcee8f 100644 --- a/src/jcgp/gui/settings/SettingsPane.java +++ b/src/jcgp/gui/settings/SettingsPane.java @@ -5,6 +5,7 @@ import java.util.ArrayList;  import javafx.event.ActionEvent;  import javafx.event.EventHandler;  import javafx.geometry.Insets; +import javafx.scene.Group;  import javafx.scene.control.Button;  import javafx.scene.control.CheckBox;  import javafx.scene.control.ComboBox; @@ -18,11 +19,13 @@ import javafx.scene.text.Text;  import jcgp.JCGP;  import jcgp.backend.function.FunctionSet;  import jcgp.backend.modules.es.EvolutionaryStrategy; -import jcgp.backend.modules.fitness.Problem;  import jcgp.backend.modules.mutator.Mutator; +import jcgp.backend.modules.problem.Problem; +import jcgp.backend.modules.problem.TestCaseProblem;  import jcgp.backend.resources.parameters.Parameter;  import jcgp.gui.GUI;  import jcgp.gui.settings.parameters.GUIParameter; +import jcgp.gui.settings.testcase.TestCaseTable;  public class SettingsPane extends AnchorPane { @@ -33,23 +36,29 @@ public class SettingsPane extends AnchorPane {  	private Button loadParameters = new Button("Load parameters"), loadChromosome = new Button("Load chromosome"), saveChromosome = new Button("Save chromosome");  	private ArrayList<GUIParameter<?>> parameters = new ArrayList<GUIParameter<?>>(); +	 +	private TestCaseTable testCaseTable; +	 +	private GUI gui; -	public SettingsPane(JCGP cgp, GUI gui) { +	public SettingsPane(GUI gui) {  		super(); +		this.gui = gui; +		final JCGP jcgp = gui.getExperiment();  		mainContainer = new VBox(8);  		mainContainer.setPadding(new Insets(5, GUI.RESIZE_MARGIN, 0, 2)); -		setMinWidth(GUI.SETTINGS_WIDTH); -		setPrefWidth(GUI.SETTINGS_WIDTH); +		setMinWidth(GUI.SETTINGS_MIN_WIDTH); +		setPrefWidth(GUI.SETTINGS_MIN_WIDTH); -		initialiseBaseParameters(cgp); +		initialiseBaseParameters(jcgp); -		initialiseEAParameters(cgp); +		initialiseEAParameters(jcgp); -		initialiseMutatorParameters(cgp); +		initialiseMutatorParameters(jcgp); -		initialiseProblemTypeParameters(cgp, gui); +		initialiseProblemTypeParameters(jcgp, gui);  		createControls(gui); @@ -66,7 +75,7 @@ public class SettingsPane extends AnchorPane {  		getChildren().add(scroll);  	} -	private void initialiseBaseParameters(JCGP cgp) { +	private void initialiseBaseParameters(JCGP jcgp) {  		baseParameterPane = new VBox(2);  		Text header = new Text("Base Parameters"); @@ -75,32 +84,32 @@ public class SettingsPane extends AnchorPane {  		baseParameterPane.getChildren().add(header); -		parameters.add(GUIParameter.create(cgp.getResources().getRowsParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getColumnsParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getInputsParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getOutputsParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getLevelsBackParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getRowsParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getColumnsParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getInputsParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getOutputsParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getLevelsBackParameter(), this)); -		GUIParameter<?> gp = GUIParameter.create(cgp.getResources().getPopulationSizeParameter(), this); +		GUIParameter<?> gp = GUIParameter.create(jcgp.getResources().getPopulationSizeParameter(), this);  		gp.setPadding(new Insets(0, 0, 10, 0));  		parameters.add(gp); -		parameters.add(GUIParameter.create(cgp.getResources().getCurrentGenerationParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getGenerationsParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getCurrentRunParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getCurrentGenerationParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getGenerationsParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getCurrentRunParameter(), this)); -		gp = GUIParameter.create(cgp.getResources().getRunsParameter(), this); +		gp = GUIParameter.create(jcgp.getResources().getRunsParameter(), this);  		gp.setPadding(new Insets(0, 0, 10, 0));  		parameters.add(gp); -		parameters.add(GUIParameter.create(cgp.getResources().getSeedParameter(), this)); -		parameters.add(GUIParameter.create(cgp.getResources().getReportParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getSeedParameter(), this)); +		parameters.add(GUIParameter.create(jcgp.getResources().getReportParameter(), this));  		baseParameterPane.getChildren().addAll(parameters);  		mainContainer.getChildren().add(baseParameterPane);  	} -	private void initialiseEAParameters(final JCGP cgp) { +	private void initialiseEAParameters(final JCGP jcgp) {  		eaPane = new VBox(2);  		Text header = new Text("Evolutionary Strategy"); @@ -108,21 +117,21 @@ public class SettingsPane extends AnchorPane {  		header.setUnderline(true);  		final ComboBox<EvolutionaryStrategy> eaCBox = new ComboBox<EvolutionaryStrategy>(); -		eaCBox.getItems().addAll(cgp.getEvolutionaryStrategies()); -		eaCBox.getSelectionModel().select(cgp.getEvolutionaryStrategy()); +		eaCBox.getItems().addAll(jcgp.getEvolutionaryStrategies()); +		eaCBox.getSelectionModel().select(jcgp.getEvolutionaryStrategy());  		eaCBox.prefWidthProperty().bind(mainContainer.widthProperty());  		final VBox eaParameters = new VBox();  		eaParameters.setSpacing(2); -		if (cgp.getEvolutionaryStrategy().getLocalParameters() != null) { -			refreshParameters(cgp.getEvolutionaryStrategy().getLocalParameters(), eaParameters); +		if (jcgp.getEvolutionaryStrategy().getLocalParameters() != null) { +			refreshParameters(jcgp.getEvolutionaryStrategy().getLocalParameters(), eaParameters);  		}  		eaCBox.setOnAction(new EventHandler<ActionEvent>() {  			@Override  			public void handle(ActionEvent event) { -				cgp.setEvolutionaryStrategy(eaCBox.getSelectionModel().getSelectedIndex()); +				jcgp.setEvolutionaryStrategy(eaCBox.getSelectionModel().getSelectedIndex());  				if (eaCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) {  					refreshParameters(eaCBox.getSelectionModel().getSelectedItem().getLocalParameters(), eaParameters);  				} @@ -133,7 +142,7 @@ public class SettingsPane extends AnchorPane {  		mainContainer.getChildren().add(eaPane);  	} -	private void initialiseMutatorParameters(final JCGP cgp) { +	private void initialiseMutatorParameters(final JCGP jcgp) {  		mutatorPane = new VBox(2);  		Text header = new Text("Mutator"); @@ -141,20 +150,20 @@ public class SettingsPane extends AnchorPane {  		header.setUnderline(true);  		final ComboBox<Mutator> mutatorCBox = new ComboBox<Mutator>(); -		mutatorCBox.getItems().addAll(cgp.getMutators()); -		mutatorCBox.getSelectionModel().select(cgp.getMutator()); +		mutatorCBox.getItems().addAll(jcgp.getMutators()); +		mutatorCBox.getSelectionModel().select(jcgp.getMutator());  		mutatorCBox.prefWidthProperty().bind(mainContainer.widthProperty());  		final VBox mutatorParameters = new VBox();  		mutatorParameters.setSpacing(2); -		if (cgp.getEvolutionaryStrategy().getLocalParameters() != null) { -			refreshParameters(cgp.getMutator().getLocalParameters(), mutatorParameters); +		if (jcgp.getEvolutionaryStrategy().getLocalParameters() != null) { +			refreshParameters(jcgp.getMutator().getLocalParameters(), mutatorParameters);  		}  		mutatorCBox.setOnAction(new EventHandler<ActionEvent>() {  			@Override  			public void handle(ActionEvent event) { -				cgp.setMutator(mutatorCBox.getSelectionModel().getSelectedIndex()); +				jcgp.setMutator(mutatorCBox.getSelectionModel().getSelectedIndex());  				if (mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) {  					refreshParameters(mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters(), mutatorParameters);  				}			 @@ -165,45 +174,72 @@ public class SettingsPane extends AnchorPane {  		mainContainer.getChildren().add(mutatorPane);   	} -	private void initialiseProblemTypeParameters(final JCGP cgp, final GUI gui) { +	private void initialiseProblemTypeParameters(final JCGP jcgp, final GUI gui) {  		problemPane= new VBox(2);  		Text header = new Text("Problem Type");  		header.setFont(Font.font("Arial", 14));  		header.setUnderline(true); -		final ComboBox<Problem> ffCBox = new ComboBox<Problem>(); -		ffCBox.getItems().addAll(cgp.getProblems()); -		ffCBox.getSelectionModel().select(cgp.getProblem()); -		ffCBox.prefWidthProperty().bind(mainContainer.widthProperty()); +		final ComboBox<Problem> problemCBox = new ComboBox<Problem>(); +		problemCBox.getItems().addAll(jcgp.getProblems()); +		problemCBox.getSelectionModel().select(jcgp.getProblem()); +		problemCBox.prefWidthProperty().bind(mainContainer.widthProperty()); +		 +		final VBox problemParameters = new VBox(); +		problemParameters.setSpacing(2); +		problemParameters.setPadding(new Insets(0, 0, 4, 0)); +		if (jcgp.getProblem().getLocalParameters() != null) { +			refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters); +		} -		final VBox ffParameters = new VBox(); -		ffParameters.setSpacing(2); -		if (cgp.getProblem().getLocalParameters() != null) { -			refreshParameters(cgp.getProblem().getLocalParameters(), ffParameters); +		final Group showTestCaseContainer = new Group(); +		final Button showTestCaseButton = makeTestCaseButton(); +		if (jcgp.getProblem() instanceof TestCaseProblem<?>) { +			showTestCaseContainer.getChildren().add(showTestCaseButton); +			 +			testCaseTable = new TestCaseTable((TestCaseProblem<Object>) jcgp.getProblem(), gui);  		}  		final VBox nodeFunctions = new VBox();  		nodeFunctions.setSpacing(2); -		refreshFunctions(cgp.getResources().getFunctionSet(), nodeFunctions, gui); +		nodeFunctions.setPadding(new Insets(0, 0, 4, 0)); +		refreshFunctions(jcgp.getResources().getFunctionSet(), nodeFunctions, gui); -		ffCBox.setOnAction(new EventHandler<ActionEvent>() { +		problemCBox.setOnAction(new EventHandler<ActionEvent>() {  			@Override  			public void handle(ActionEvent event) { -				cgp.setProblem(ffCBox.getSelectionModel().getSelectedIndex()); -				if (ffCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) { -					refreshParameters(cgp.getProblem().getLocalParameters(), ffParameters); -					refreshFunctions(cgp.getProblem().getFunctionSet(), nodeFunctions, gui); +				jcgp.setProblem(problemCBox.getSelectionModel().getSelectedIndex()); +				if (jcgp.getProblem().getLocalParameters() != null) { +					showTestCaseContainer.getChildren().clear(); +					refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters); +					refreshFunctions(jcgp.getProblem().getFunctionSet(), nodeFunctions, gui); +					testCaseTable.close(); +					if (jcgp.getProblem() instanceof TestCaseProblem) { +						showTestCaseContainer.getChildren().add(showTestCaseButton); +						testCaseTable = new TestCaseTable((TestCaseProblem<Object>) jcgp.getProblem(), gui); +					}  				}  				gui.reset();  			}  		}); -		problemPane.getChildren().addAll(header, ffCBox, ffParameters, nodeFunctions);  +		problemPane.getChildren().addAll(header, problemCBox, problemParameters, nodeFunctions, showTestCaseContainer);   		mainContainer.getChildren().add(problemPane);  	} +	private Button makeTestCaseButton() { +		Button b = new Button("Show test cases"); +		b.setOnAction(new EventHandler<ActionEvent>() { +			@Override +			public void handle(ActionEvent event) { +				testCaseTable.show();  +			} +		}); +		return b; +	} +  	private void createControls(final GUI gui) {  		Text header = new Text("Experiment controls");  		header.setFont(Font.font("Arial", 14)); @@ -291,31 +327,43 @@ public class SettingsPane extends AnchorPane {  		revalidateParameters();  	} -	private void refreshFunctions(final FunctionSet fs, VBox vb, final GUI gui) { -		vb.getChildren().clear(); +	/** +	 * This method handles a problem type change by updating the list of allowed +	 * node functions. +	 *  +	 * @param functionSet  +	 * @param container +	 * @param gui +	 */ +	private void refreshFunctions(final FunctionSet functionSet, VBox container, final GUI gui) { +		container.getChildren().clear();  		CheckBox cb; -		for (int i = 0; i < fs.getTotalFunctionCount(); i++) { -			cb = new CheckBox(fs.getFunction(i).getName()); +		for (int i = 0; i < functionSet.getTotalFunctionCount(); i++) { +			cb = new CheckBox(functionSet.getFunction(i).getName());  			cb.setId(String.valueOf(i)); -			cb.setSelected(fs.isEnabled(fs.getFunction(i))); +			cb.setSelected(functionSet.isEnabled(functionSet.getFunction(i)));  			final int index = i;  			cb.setOnAction(new EventHandler<ActionEvent>() {  				@Override  				public void handle(ActionEvent event) {  					if (((CheckBox) event.getSource()).isSelected()) { -						fs.enableFunction(index); +						functionSet.enableFunction(index);  					} else { -						fs.disableFunction(index); +						functionSet.disableFunction(index);  					} -					GUI.updateFunctionSelector(); +					gui.updateFunctionSelector();  				}  			}); -			vb.getChildren().add(cb); +			container.getChildren().add(cb); -			GUI.updateFunctionSelector(); +			gui.updateFunctionSelector();  		}  	} +	public boolean isExperimentRunning() { +		return gui.isWorking(); +	} +	  	/**  	 *   	 * @return true if the experiment needs to be reset, false otherwise. @@ -329,6 +377,9 @@ public class SettingsPane extends AnchorPane {  		return false;  	} +	/** +	 * @return true if no parameters have their status set to ParameterStatus.INVALID. +	 */  	public boolean areParametersValid() {  		for (GUIParameter<?> parameter : parameters) {  			if (!parameter.isValid()) { @@ -338,6 +389,11 @@ public class SettingsPane extends AnchorPane {  		return true;  	} +	/** +	 * Calls validate() on every parameter. This is called whenever a parameter changes, +	 * so that other parameters update their status in case they were dependent on the +	 * changed parameter. +	 */  	public void revalidateParameters() {  		runPause.setDisable(false);  		for (GUIParameter<?> parameter : parameters) { @@ -348,12 +404,24 @@ public class SettingsPane extends AnchorPane {  		}  	} +	/** +	 * Calls applyValue() on every parameter. This is called when a reset occurs, so that +	 * the new value will be used as a reference instead of the old reference value. +	 */  	public void applyParameters() {  		for (GUIParameter<?> parameter : parameters) {  			parameter.applyValue();  		}  	} +	/** +	 * Updates all of the controls to their appropriate state based on the status of the +	 * experiment, in order to prevent inappropriate operations if the experiment is +	 * running or finished. +	 *  +	 * @param running true if the experiment is running +	 * @param finished true if the experiment is finished +	 */  	public void updateControls(boolean running, boolean finished) {  		baseParameterPane.setDisable(running);  		eaPane.setDisable(running); @@ -361,8 +429,13 @@ public class SettingsPane extends AnchorPane {  		problemPane.setDisable(running);  		runPause.setText(running ? "Pause" : "Run"); +		System.out.println("[updateControls] run pause disable: " + finished);  		runPause.setDisable(finished);  		step.setDisable(running || finished);  		reset.setDisable(running);  	} +	 +	public TestCaseTable getTestCaseTable() { +		return testCaseTable; +	}  } diff --git a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java index bada5d4..e708c53 100644 --- a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java @@ -6,7 +6,6 @@ import javafx.scene.control.CheckBox;  import javafx.scene.control.Control;  import jcgp.backend.resources.parameters.BooleanParameter;  import jcgp.backend.resources.parameters.ParameterStatus; -import jcgp.gui.GUI;  import jcgp.gui.settings.SettingsPane;  /** @@ -40,7 +39,7 @@ public class GUIBooleanParameter extends GUIParameter<Boolean> {  	}  	@Override -	protected void setControlListeners(final SettingsPane sp) { +	protected void setControlListeners() {  		/* pass the CheckBox value back to the parameter whenever it gets  		 * modified, provided the experiment isn't running */  		checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() { @@ -48,9 +47,9 @@ public class GUIBooleanParameter extends GUIParameter<Boolean> {  			public void changed(  					ObservableValue<? extends Boolean> observable,  					Boolean oldValue, Boolean newValue) { -				if (!GUI.isWorking()) { +				if (!settingsPane.isExperimentRunning()) {  					parameter.set(newValue); -					sp.revalidateParameters(); +					settingsPane.revalidateParameters();  				}  			}  		}); diff --git a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java index 87e7b69..29648ca 100644 --- a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java @@ -9,7 +9,6 @@ import javafx.scene.control.TextField;  import javafx.scene.input.KeyEvent;  import jcgp.backend.resources.parameters.Parameter;  import jcgp.backend.resources.parameters.ParameterStatus; -import jcgp.gui.GUI;  import jcgp.gui.settings.SettingsPane;  /** @@ -44,7 +43,7 @@ public class GUIDoubleParameter extends GUIParameter<Number> {  	}  	@Override -	protected void setControlListeners(final SettingsPane sp) { +	protected void setControlListeners() {  		/* filter keypresses and ignore anything that is not a number  		 * and any decimal point beyond the first ones */  		textField.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() { @@ -63,9 +62,9 @@ public class GUIDoubleParameter extends GUIParameter<Number> {  			public void changed(  					ObservableValue<? extends String> observable,  					String oldValue, String newValue) { -				if (!newValue.isEmpty() && !GUI.isWorking()) { +				if (!newValue.isEmpty() && !settingsPane.isExperimentRunning()) {  					parameter.set(Double.parseDouble(newValue)); -					sp.revalidateParameters(); +					settingsPane.revalidateParameters();  				}  			} diff --git a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java index 6927f26..da2c11f 100644 --- a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java @@ -9,7 +9,6 @@ import javafx.scene.control.TextField;  import javafx.scene.input.KeyEvent;  import jcgp.backend.resources.parameters.Parameter;  import jcgp.backend.resources.parameters.ParameterStatus; -import jcgp.gui.GUI;  import jcgp.gui.settings.SettingsPane;  /** @@ -44,7 +43,7 @@ public class GUIIntegerParameter extends GUIParameter<Number> {  	}  	@Override -	protected void setControlListeners(final SettingsPane settingsPane) { +	protected void setControlListeners() {  		/* filter keypresses and ignore anything that is not a number */  		textField.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {  			@Override @@ -62,7 +61,7 @@ public class GUIIntegerParameter extends GUIParameter<Number> {  			public void changed(  					ObservableValue<? extends String> observable,  					String oldValue, String newValue) { -				if (!newValue.isEmpty() && !GUI.isWorking()) { +				if (!newValue.isEmpty() && !settingsPane.isExperimentRunning()) {  					parameter.set(Double.parseDouble(newValue));  					settingsPane.revalidateParameters();  				} diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java index b7afb74..a8a8c4a 100644 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIParameter.java @@ -49,6 +49,7 @@ public abstract class GUIParameter<T> extends HBox {  	private Text name;  	private Control valueControl; +	protected SettingsPane settingsPane;  	protected Tooltip tooltip;  	protected Parameter<T> parameter; @@ -70,24 +71,24 @@ public abstract class GUIParameter<T> extends HBox {  	 * @param parameter a Parameter for which to generate a GUIParameter  	 * @param sp a reference to the SettingsPane  	 */ -	protected GUIParameter(Parameter<T> parameter, final SettingsPane sp) { +	protected GUIParameter(Parameter<T> parameter, final SettingsPane settingsPane) {  		this.parameter = parameter;  		this.referenceValue = parameter.get(); +		this.settingsPane = settingsPane; +		  		setAlignment(Pos.CENTER_LEFT);  		setSpacing(5);  		name = new Text(parameter.getName());  		// set text width to half of the total width of the GUIParameter  		name.wrappingWidthProperty().bind(widthProperty().divide(2)); -		// allow the text to grow to always fill half of the GUIParameter  		// the tooltip is the hover-over label containing status information, when appropriate  		tooltip = new Tooltip();  		tooltip.setStyle("-fx-background-color: white; -fx-border-color: black; .page-corner {-fx-background-color: transparent;}");  		tooltip.setSkin(null); -		  		valueControl = makeControl();  		setHgrow(valueControl, Priority.ALWAYS); @@ -99,7 +100,7 @@ public abstract class GUIParameter<T> extends HBox {  		// if parameter is not a monitor, make sure the control is constrained appropriately  		if (!parameter.isMonitor()) { -			setControlListeners(sp); +			setControlListeners();  		}  		getChildren().addAll(name, valueControl); @@ -143,7 +144,7 @@ public abstract class GUIParameter<T> extends HBox {  					ObservableValue<? extends Object> observable,  					Object oldValue, Object newValue) {  				// only do this if the experiment is running -				if (GUI.isWorking()) { +				if (settingsPane.isExperimentRunning()) {  					/* here's the catch - atomically get the lock state and set it to true  					 * the lock will only be false again when the runnable is finished executing,   					 * preventing multiple runnables to concurrently update the same GUIParameter @@ -221,11 +222,11 @@ public abstract class GUIParameter<T> extends HBox {  	 * presses to ensure no invalid characters are inserted, applying the new   	 * value to the underlying parameter and revalidating the parameters to  	 * reflect the changes made. -	 *  -	 * @param settingsPane the parent Pane on which revalidateParameters() should -	 * be called. +	 * <br><br> +	 * Note that changelisteners registered to the main content property of the +	 * control should always call handleChange() to update the   	 */ -	protected abstract void setControlListeners(SettingsPane settingsPane); +	protected abstract void setControlListeners();  	/**  	 * This method is called to style the GUIParameter according to the status of diff --git a/src/jcgp/gui/settings/testcase/TestCaseTable.java b/src/jcgp/gui/settings/testcase/TestCaseTable.java new file mode 100644 index 0000000..7e72cbd --- /dev/null +++ b/src/jcgp/gui/settings/testcase/TestCaseTable.java @@ -0,0 +1,90 @@ +package jcgp.gui.settings.testcase; + +import java.util.ArrayList; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.scene.Scene; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableColumn.CellDataFeatures; +import javafx.scene.control.TableView; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; +import javafx.util.Callback; +import jcgp.backend.modules.problem.TestCaseProblem; +import jcgp.backend.modules.problem.TestCaseProblem.TestCase; +import jcgp.gui.GUI; + +/** + * Dont forget to override toString()! + *  + *  + * @author Eduardo Pedroni + * + */ +public class TestCaseTable extends Stage { + +	public TestCaseTable(final TestCaseProblem<Object> problem, final GUI gui) { +		super(); +		 +		TableView<TestCase<Object>> tv = new TableView<TestCase<Object>>(); +		ObservableList<TestCase<Object>> testCaseList = problem.getTestCases(); +		 +		ArrayList<TableColumn<TestCase<Object>, String>> inputs = new ArrayList<TableColumn<TestCase<Object>, String>>(problem.getInputCount()); +		ArrayList<TableColumn<TestCase<Object>, String>> outputs = new ArrayList<TableColumn<TestCase<Object>, String>>(problem.getOutputCount()); + +		TableColumn<TestCase<Object>, String> tc; +		for (int i = 0; i < problem.getInputCount(); i++) { +			tc = new TableColumn<TestCase<Object>, String>("I: " + i); +			inputs.add(tc); +			final int index = i; +			tc.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<TestCase<Object>,String>, ObservableValue<String>>() { +				@Override +				public ObservableValue<String> call(CellDataFeatures<TestCase<Object>, String> param) { +					return new SimpleStringProperty(param.getValue().getInput(index).toString()); +				} +			}); +			tc.setSortable(false); +			tc.prefWidthProperty().bind(tv.widthProperty().divide(problem.getInputCount() + problem.getOutputCount())); +		} +		 +		for (int o = 0; o < problem.getOutputCount(); o++) { +			tc = new TableColumn<TestCase<Object>, String>("O: " + o); +			outputs.add(tc); +			final int index = o; +			tc.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<TestCase<Object>,String>, ObservableValue<String>>() { +				@Override +				public ObservableValue<String> call(CellDataFeatures<TestCase<Object>, String> param) { +					return new SimpleStringProperty(param.getValue().getOutput(index).toString()); +				} +			}); +			tc.setSortable(false); +			tc.prefWidthProperty().bind(tv.widthProperty().divide(problem.getInputCount() + problem.getOutputCount())); +		} +		 +		tv.getColumns().addAll(inputs); +		tv.getColumns().addAll(outputs); +		 +		tv.setItems(testCaseList); +		 +		tv.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TestCase<Object>>() { +			@Override +			public void changed( +					ObservableValue<? extends TestCase<Object>> observable,	TestCase<Object> oldValue, TestCase<Object> newValue) { +				gui.evaluateTestCase(newValue); +			} +		}); +		 +		setOnCloseRequest(new EventHandler<WindowEvent>() { +			@Override +			public void handle(WindowEvent event) { +				gui.hideGeneValues(); +			} +		}); +		 +		setScene(new Scene(tv)); +	} +} | 
