diff options
Diffstat (limited to 'src/jcgp/population/Chromosome.java')
| -rw-r--r-- | src/jcgp/population/Chromosome.java | 198 | 
1 files changed, 144 insertions, 54 deletions
diff --git a/src/jcgp/population/Chromosome.java b/src/jcgp/population/Chromosome.java index 0dc3ff9..1f264f2 100644 --- a/src/jcgp/population/Chromosome.java +++ b/src/jcgp/population/Chromosome.java @@ -1,5 +1,7 @@  package jcgp.population; +import java.util.ArrayList; +  import jcgp.Parameters;  import jcgp.Utilities;  import jcgp.fitness.ParameterMismatchException; @@ -9,11 +11,15 @@ public class Chromosome {  	private Input[] inputs;  	private Node[][] nodes;  	private Output[] outputs; +	 +	private ArrayList<Connection> activeNodes;  	private int fitness = 0; +	private boolean recomputeActiveNodes = true;  	/** -	 * Good citizen. +	 * Initialise a chromosome with the specified parameters. Random valid connections +	 * are created.  	 *   	 * @param outputs   	 * @param columns  @@ -21,61 +27,110 @@ public class Chromosome {  	 * @param inputs   	 *   	 */ -	public Chromosome(int inputCount, int rows, int columns, int outputCount) { - -		instantiateElements(inputCount, rows, columns, outputCount); - +	public Chromosome() { +		// allocate memory for all elements of the chromosome +		instantiateElements(); +		// set random connections so that the chromosome can be evaluated  		initialiseConnections(); +	} +	/** +	 * Copy constructor. +	 *  +	 * Initialise a new chromosome with the exact same connections as a given instance of Chromosome. +	 *  +	 * @param clone the chromosome to be copied +	 */ +	public Chromosome(Chromosome clone) { +		// allocate memory for all elements of the chromosome +		instantiateElements(); +		// initialise all connections based on argument +		copyConnections(clone);  	}  	/** -	 * @param inputCount -	 * @param rows -	 * @param columns -	 * @param outputCount +	 *  	 */ -	private void instantiateElements(int inputCount, int rows, int columns,	int outputCount) { -		inputs = new Input[inputCount]; -		for (int i = 0; i < inputCount; i++) { -			inputs[i] = new Input(); +	private void instantiateElements() { +		inputs = new Input[Parameters.getInputs()]; +		for (int i = 0; i < Parameters.getInputs(); i++) { +			inputs[i] = new Input(i);  		}  		// rows first -		nodes = new Node[rows][columns]; -		for (int r = 0; r < rows; r++) { -			//nodes[r] = new Node[Parameters.getColumns()]; -			for (int c = 0; c < columns; c++) { -				nodes[r][c] = new Node(r, c); +		nodes = new Node[Parameters.getRows()][Parameters.getColumns()]; +		for (int r = 0; r < Parameters.getRows(); r++) { +			for (int c = 0; c < Parameters.getColumns(); c++) { +				nodes[r][c] = new Node(this, r, c);  			}  		} -		outputs = new Output[outputCount]; -		for (int o = 0; o < outputCount; o++) { -			outputs[o] = new Output(o); +		outputs = new Output[Parameters.getOutputs()]; +		for (int o = 0; o < Parameters.getOutputs(); o++) { +			outputs[o] = new Output(this, o);  		}  	} +	/** +	 *  +	 */  	private void initialiseConnections() {  		// initialise nodes - [rows][columns]  		for (int r = 0; r < nodes.length; r++) { -			for (int c = 0; c < nodes.length; c++) { +			for (int c = 0; c < nodes[r].length; c++) {  				Connection[] connections = new Connection[Parameters.getMaxArity()];  				for (int i = 0; i < connections.length; i++) { -					connections[i] = Utilities.getRandomConnection(this, c); +					connections[i] = getRandomConnection(c);  				}  				nodes[r][c].initialise(Utilities.getRandomFunction(), connections);  			}  		}  		for (Output output : outputs) { -			output.setConnection(Utilities.getRandomNode(this)); +			output.setConnection(getRandomConnection());  		}  	} -	public int getActiveNodeCount() { -		return 0; +	/** +	 * @param clone +	 */ +	private void copyConnections(Chromosome clone) { +		// copy nodes - [rows][columns] +		for (int r = 0; r < nodes.length; r++) { +			for (int c = 0; c < nodes[r].length; c++) { +				// make array of connections to initialise with +				Connection[] connections = new Connection[Parameters.getMaxArity()]; +				// populate with connections equivalent to clone +				Connection copyConnection; +				for (int i = 0; i < connections.length; i++) { +					copyConnection = clone.getNode(r, c).getConnections(i); +					if (copyConnection instanceof Input) { +						connections[i] = inputs[((Input) copyConnection).getIndex()]; +					} 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."); +					} +				} +				// initialise with copied arguments +				nodes[r][c].initialise(clone.getNode(r, c).getFunction(), connections); +			} +		} +		 +		// do the same to outputs +		Connection copyOutput; +		for (int o = 0; o < outputs.length; o++) { +			copyOutput = clone.getOutput(o).getSource(); +			if (copyOutput instanceof Input) { +				outputs[o].setConnection(inputs[((Input) copyOutput).getIndex()]); +			} else if (copyOutput instanceof Node) { +				outputs[o].setConnection(nodes[((Node) copyOutput).getRow()][((Node) copyOutput).getColumn()]); +			} else { +				// something bad happened +				System.out.println("Warning: Connection of subtype " + copyOutput.getClass().toString() + " is not explicitly handled by copy constructor."); +			} +		}  	}  	public Node getNode(int row, int column) { @@ -110,6 +165,11 @@ public class Chromosome {  		}  	} +	/** +	 * This method is useful for mutating chromosomes. +	 *  +	 * @return a random element that can be mutated - Node or Output +	 */  	public MutableElement getRandomMutableElement() {  		// choose output or node  		int index = Utilities.getRandomInt(outputs.length + Parameters.getNodeCount()); @@ -123,9 +183,9 @@ public class Chromosome {  			return nodes[index / Parameters.getColumns()][index % Parameters.getColumns()];  		}  	} -	 +  	/** -	 * Returns a random allowed connection respecting levels back. +	 * Returns a random allowed connection respecting levels back.</br>  	 * This method may always pick inputs, as they can be picked  	 * regardless of the column.  	 *  @@ -133,41 +193,71 @@ public class Chromosome {  	 * @return a random connection  	 */  	public Connection getRandomConnection(int column) { -		 -		 -		 -		return null; -		 +		// work out the allowed range obeying levels back +		int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); +		int offset = ((column - allowedColumns) * nodes.length) - inputs.length; + +		// choose input or allowed node +		int index = Utilities.getRandomInt(inputs.length + (nodes.length * allowedColumns)); +		if (index < inputs.length) { +			// input +			return inputs[index]; +		} else { +			// node	 +			// offset it to address the right columns +			index += offset; +			return nodes[index % nodes.length][index / nodes.length]; +		}  	} -	 +  	/** -	 * Returns a random allowed connection.  +	 * This method will pick a completely random connection, independently +	 * of levels back, including inputs.  	 *  -	 * This method may always pick inputs, as they can be picked -	 * regardless of the column. +	 * Useful for setting outputs.  	 *  -	 * TODO optimise for less random generations  	 *  -	 * @param column the column to use as reference -	 * @param levelsBack whether or not to respect levels back  	 * @return a random connection  	 */ -	public Connection getRandomConnection(int column, boolean levelsBack) { -		 -		if (levelsBack) { -			return getRandomConnection(chromosome, column); +	public Connection getRandomConnection() { +		// choose output or node +		int index = Utilities.getRandomInt(inputs.length + Parameters.getNodeCount()); + +		if (index < inputs.length) { +			// outputs +			return inputs[index];  		} else { -			// choose input or node -			int connectionType = Utilities.getRandomInt(inputs.length + (nodes.length * column)); -			if (connectionType < inputs.length) { -				// input -				return chromosome.getInput(getRandomInt(Parameters.getInputs())); -			} else { -				// node				 -				return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(column)); -			} +			// node	 +			index -= inputs.length; +			return nodes[index / Parameters.getColumns()][index % Parameters.getColumns()];  		} -		 +	} +	 +	/** +	 * This causes the list of active nodes to be recomputed lazily (once it is actually requested). +	 */ +	public void recomputeActiveNodes() { +		recomputeActiveNodes = true; +	} +	 +	/** +	 * This method computes a list of active nodes (if necessary) and returns it. +	 * +	 * @return +	 */ +	public ArrayList<Connection> getActiveNodes() { +		// lazy recomputation has been triggered, do it +		if (recomputeActiveNodes) { +			recomputeActiveNodes = false; +			activeNodes = new ArrayList<Connection>(); +			 +			for (int r = 0; r < nodes.length; r++) { +				for (int c = 0; c < nodes[r].length; c++) { +					 +				} +			} +		}		 +		return activeNodes;  	}  }  | 
