/* * Copyright 2007-2013 * Licensed under GNU Lesser General Public License * * This file is part of EpochX: genetic programming software for research * * EpochX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * EpochX is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with EpochX. If not, see <http://www.gnu.org/licenses/>. * * The latest version is available from: http://www.epochx.org */ package org.epochx.stgp; import org.apache.commons.lang.ObjectUtils; import org.epochx.*; import org.epochx.Config.ConfigKey; import org.epochx.epox.*; /** * An <code>STGPIndividual</code> is a candidate solution which uses a strongly * typed tree representation to represent a computer program. This class * provides several convenient methods for obtaining information about the * program tree (such as {@link #length()} and {@link #depth()}), but more * information is available directly from the tree. Use {@link #getRoot()} to * get access to the tree. * * <p> * Note: this class has a natural ordering that may be inconsistent with * <code>equals</code>. * * @since 2.0 */ public class STGPIndividual extends AbstractIndividual { private static final long serialVersionUID = -1428100428151029601L; /** * The key for setting and retrieving the set of nodes that individuals are * constructed from */ public static final ConfigKey<Node[]> SYNTAX = new ConfigKey<Node[]>(); /** * The key for setting and retrieving the required data-type for the root * node */ public static final ConfigKey<Class<?>> RETURN_TYPE = new ConfigKey<Class<?>>(); /** * The key for setting and retrieving the maximum depth setting for program * trees */ public static final ConfigKey<Integer> MAXIMUM_DEPTH = new ConfigKey<Integer>(); // The root node of the program tree private Node root; /** * Constructs an individual represented by a strongly typed tree, with * a <code>null</code> root node */ public STGPIndividual() { this(null); } /** * Constructs an individual represented by a strongly typed tree, where * <code>root</code> is the root node of the tree * * @param root the <code>Node</code> to set as the root */ public STGPIndividual(Node root) { this.root = root; } /** * Evaluates the strongly typed program tree this individual represents and * returns the value returned from the root. If no root node has been set then * an exception will be thrown. * * @return the result of evaluating the program tree */ public Object evaluate() { return root.evaluate(); } /** * Returns the <code>Node</code> that is set as the root of the program tree * * @return the root node of the program tree. */ public Node getRoot() { return root; } /** * Replaces the <code>Node</code> that is set as the root of the program tree * * @param root the <code>Node</code> to set as the root */ public void setRoot(Node root) { this.root = root; } /** * Returns the <i>n</i>th node in the program tree. The tree is traversed in * pre-order (depth-first), indexed from 0 so that the root node is at * index 0. * * @param index index of the node to return * @return the node at the specified index * @throws IndexOutOfBoundsException if the index is out of range (index < 0 * || index >= getLength()) */ public Node getNode(int index) { if (index >= 0) { return root.getNode(index); } else { throw new IndexOutOfBoundsException("attempt to get node at negative index"); } } /** * Replaces the node at the specified position in the program tree with the * specified node. * * @param index index of the node to be replaced * @param node node to be set at the specified position * @return the node previously at this position * @throws IndexOutOfBoundsException if the index is out of range (index < 0 * || index >= getLength()) */ public Node setNode(int index, Node node) { if (index > 0) { return root.setNode(index, node); } else if (index == 0) { Node old = getRoot(); setRoot(node); return old; } else { // We rely on Node to throw exception if index >= length. It's too // expensive to check here. throw new IndexOutOfBoundsException("attempt to set node at negative index"); } } /** * Returns the maximum depth of the program tree. The depth of a tree is * defined as the length of the path from the root to the deepest node in * the tree. For a tree with just one node (the root), the depth is 0. * * @return the maximum depth of the program tree */ public int depth() { return getRoot().depth(); } /** * Returns the total number of nodes in the program tree * * @return the number of nodes in the program tree. */ public int length() { return getRoot().length(); } /** * Returns the data-type of the values returned by the program tree * * @return the object <code>Class</code> of the values returned */ public Class<?> dataType() { return getRoot().dataType(); } /** * Creates and returns a copy of this program. The copied individual has a * deep clone of the program tree. The clone is not assigned this individual's * fitness. * * @return a clone of this <code>STGPIndividual</code> instance */ @Override public STGPIndividual clone() { STGPIndividual clone = (STGPIndividual) super.clone(); // Deep copy node tree if (root == null) { clone.root = null; } else { clone.root = root.clone(); } return clone; } /** * Returns a string representation of this individual. The string representation is the * Epox source code of the program tree. * * @return a string representation of this individual */ @Override public String toString() { if (root == null) { return null; } else { return root.toString(); } } /** * Compares the given object to this instance for equality. Equivalence is * defined as them both being instances of <code>STGPIndividual</code> and * having equal program trees according to <code>getRoot().equals(obj)</code> * (or if both root nodes are <code>null</code>). * * @param obj an object to be compared for equivalence. * @return true if this individual is equivalent to the specified object and * false otherwise. */ @Override public boolean equals(Object obj) { boolean equal = false; if ((obj != null) && (obj instanceof STGPIndividual)) { STGPIndividual p = (STGPIndividual) obj; if (ObjectUtils.equals(root, p.root)) { equal = true; } } return equal; } /** * Returns a hash code value for the object. * * @return a hash code value for this object */ @Override public int hashCode() { int hash = 1; hash = hash * 13 + (root == null ? 0 : root.hashCode()); return hash; } /** * Compares this individual to another based on their fitness. It returns a * negative integer, zero, or a positive integer as this instance represents * the quality of an individual that is less fit, equally fit, or more fit * than the specified object. The individuals do not need to be of the same * object type, but must have non-null, comparable <code>Fitness</code> instances. * * @param other an individual to compare against * @return a negative integer, zero, or a positive integer as this object is * less fit than, equally fit as, or fitter than the specified * object */ @Override public int compareTo(Individual other) { return getFitness().compareTo(other.getFitness()); } }