/* * Copyright 2007-2013 * Licensed under GNU Lesser General Public License * * This file is part of EpochX * * 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.monitor.graph; import java.io.Serializable; import java.util.ArrayList; import org.epochx.Fitness; import org.epochx.Individual; import org.epochx.Operator; import org.epochx.event.OperatorEvent.EndOperator; /** * A <code>GraphVertex</code> encloses an <code>Individual</code> to be * represented in a graph. * * <p> * An instance can stores extra informations about the <code>Individual</code> : * <ul> * <li>The parent <code>GraphGeneration</code>. * <li>The <code>Operator</code> responsible for this individual. * <li>The <code>EndOperator</code> event responsible for this individual. * <li>The rank of this individual among its siblings. * <li>A list of parent <code>GraphVertex</code>. * <li>A list of children <code>GraphVertex</code>. * <p> */ public class GraphVertex implements Comparable<Object>, Serializable { /** * Generated serial UID. */ private static final long serialVersionUID = 654188368821480724L; /** * The parent <code>GraphGeneration</code>. */ private GraphGeneration graphGeneration; /** * The <code>Individual</code>. */ private Individual individual; /** * The <code>Operator</code>. */ private Operator operator; /** * The Operator event. */ private EndOperator operatorEvent; /** * The rank of this individual among the siblings. */ private int rank; /** * The list of parents. */ private ArrayList<GraphVertex> parents; /** * The list of children. */ private transient ArrayList<GraphVertex> children; /** * Constructs a <code>GraphVertex</code>. * * @param graphGeneration the parent <code>GraphGeneration</code>. * @param individual the <code>Individual</code> whose this * <code>GraphVertex</code> is the representation. */ public GraphVertex(GraphGeneration graphGeneration, Individual individual) { if (individual == null) { throw new NullPointerException("The individual cannot be null."); } this.individual = individual; this.graphGeneration = graphGeneration; this.operator = null; this.operatorEvent = null; this.rank = -1; this.parents = new ArrayList<GraphVertex>(); this.children = new ArrayList<GraphVertex>(); } /** * Returns the invididual. * * @return the individual. */ public Individual getIndividual() { return individual; } /** * Sets the individual. * * @param individual the individual to set */ public void setIndividual(Individual individual) { this.individual = individual; } /** * Delegate method ; Returns the individual's <code>Fitness</code>. * * @return the individual's <code>Fitness</code>. */ public Fitness getFitness() { return individual.getFitness(); } /** * Returns the graphGeneration. * * @return the graphGeneration. */ public GraphGeneration getGraphGeneration() { return graphGeneration; } /** * Sets the graphGeneration. * * @param graphGeneration the graphGeneration to set. */ public void setGraphGeneration(GraphGeneration graphGeneration) { this.graphGeneration = graphGeneration; } /** * Delegate method ; Returns the generation number. * * @return the generation number. */ public int getGenerationNo() { return graphGeneration.getGeneration(); } /** * Returns the parent <code>Operator</code>. * * @return the parent <code>Operator</code>; Can be null. */ public Operator getOperator() { return operator; } /** * Sets the parent <code>Operator</code>. * * @param operator the operator to set. */ public void setOperator(Operator operator) { this.operator = operator; } /** * Returns the parent <code>EndOperator</code> event. * * @return the parent <code>EndOperator</code> event; Can be null. */ public EndOperator getOperatorEvent() { return operatorEvent; } /** * Sets the parent <code>EndOperator</code> event. * * @param operatorEvent the parent <code>EndOperator</code> event to set. */ public void setOperatorEvent(EndOperator operatorEvent) { this.operatorEvent = operatorEvent; } /** * Returns the rank of this individual among the siblings. * * @return the rank of this individual among the siblings. */ public int getRank() { return rank; } /** * Sets the rank of this individual among the siblings. * * @param rank the rank to set. */ public void setRank(int rank) { this.rank = rank; } /** * Returns the array of this vertex's parents. * * @return the array of this vertex's parents. */ public GraphVertex[] getParents() { GraphVertex[] vertices = null; if (parents != null) { synchronized (parents) { vertices = new GraphVertex[parents.size()]; parents.toArray(vertices); } } return vertices; } /** * Adds vertices to the list of parents. * * @param parentVertices vertices to add. */ public void addParents(GraphVertex ... parentVertices) { if (parents == null) { parents = new ArrayList<GraphVertex>(); } synchronized (parents) { for (GraphVertex parentVertex: parentVertices) { parents.add(parentVertex); parentVertex.addChildren(this); } } } /** * Clears the parent list. */ public void clearParents() { if (parents != null) { synchronized (parents) { this.parents.clear(); } } else { parents = new ArrayList<GraphVertex>(); } } /** * Returns the array of this vertex's children. * * @return the array of this vertex's children. */ public GraphVertex[] getChildren() { GraphVertex[] vertices = null; if (children != null) { synchronized (children) { vertices = new GraphVertex[children.size()]; children.toArray(vertices); } } return vertices; } /** * Adds vertices to the list of children. * * @param childrenVertices vertices to add. */ public void addChildren(GraphVertex ... childrenVertices) { if (children == null) { children = new ArrayList<GraphVertex>(); } synchronized (children) { for (GraphVertex childVertex: childrenVertices) { children.add(childVertex); } } } /** * Clears the children list. */ public void clearChildren() { if (children != null) { synchronized (children) { this.children.clear(); } } else { children = new ArrayList<GraphVertex>(); } } /** * Returns the siblings of this vertex among its parent generation. * * @return the siblings of this vertex among its parent generation. */ public GraphVertex[] getSiblings() { return graphGeneration.getSiblings(this); } /** * Returns the index of this node in the generation list of vertices. * * @return the index of this node in the generation list of vertices. * @see GraphGeneration#vertices * @see GraphGeneration#indexOf(Object) */ public int getIndex() { return graphGeneration.indexOf(this); } /** * Returns the mean of indices of this vertex's parents. * * @return the mean of indices of this vertex's parents. */ public double getParentMeanIndex() { double mean = 0; for (GraphVertex parent: parents) { mean += parent.getIndex(); } mean /= parents.size(); return mean; } /** * Returns the genitor's vertex. The genitor is the individual from which * this individual has been cloned before being modified. * * @return the genitor of this vertex if it can be determined; null, * otherwise. */ public GraphVertex genitor() { GraphVertex res = null; if (operatorEvent != null && operator != null) { // Case 1 : only one parent. if (operator.inputSize() == 1 && parents.size() > 0) { res = parents.get(0); } // Case 2 : two parents. if (operator.inputSize() == 2 && 0 <= rank && rank < getParents().length) { res = parents.get(rank); } } return res; } /** * Returns the index of the point from the genitor which has been * mutated.The point among the points array of the <code>EndOperator</code> * event corresponding to the rank of this vertex. * * @return the index of the point from the genitor which has been * mutated if the <code>EndOperator</code> event has been defined; * returns -1, otherwise. */ public int genitorPoint() { int res = -1; if (operatorEvent != null && 0 <= rank && rank < operatorEvent.getPoints().length) { res = operatorEvent.getPoints()[rank]; } return res; } /** * Returns the provider's vertex. The provider is the individual which has * supplied genes to create this individual. * <p> * For example, during a <i>Crossover</i> operation, the provider is the * second parent; For a <i>Mutation</i>, there is no provider as the mutated * part has been newly created. * </p> * * @return the provider of this vertex if it exists; null, otherwise. */ public GraphVertex provider() { GraphVertex res = null; if (operator != null) { // Case 2 : two parents. if (operator.inputSize() == 2 && 0 <= rank && rank < getParents().length) { res = parents.get(1 - rank); } } return res; } /** * Returns the index of the sub-tree which is the supplied gene to create * this individual among the provider tree. * * @return the provider point if the <code>EndOperator</code> event has * been defined; returns -1, otherwise. */ public int providerPoint() { int res = -1; if (operatorEvent != null && 0 <= rank && rank < operatorEvent.getPoints().length) { res = operatorEvent.getPoints()[operatorEvent.getPoints().length - 1 - rank]; } return res; } /** * Compares the given object with this <code>GraphVertex</code>'s * <code>Fitness</code>. * * <p> * The given object can be an instance of <code>GraphVertex</code> or * <code>Individual</code>. Throws a <code>ClassCastException</code> * otherwise. * </p> * * @param obj the reference object with which to compare * @return the value 0 if the argument's <code>Fitness</code> is equal to * this <code>GraphVertex</code>'s <code>Fitness</code>; a value * less than 0 if the argument's <code>Fitness</code> is than this * <code>GraphVertex</code>'s <code>Fitness</code>; and a value * greater than 0 if the argument's <code>Fitness</code> is less * than this <code>GraphVertex</code>'s <code>Fitness</code>. * * @throws ClassCastException if the given object is not an instance of * <code>GraphVertex</code> or <code>Individual</code>. */ public int compareTo(Object obj) throws ClassCastException { if (obj instanceof GraphVertex) { return getFitness().compareTo(((GraphVertex) obj).getFitness()); } else if (obj instanceof Individual) { return getFitness().compareTo(((Individual) obj).getFitness()); } else { throw new ClassCastException(obj.getClass().getSimpleName()); } } /** * Overrides the <code>equals</code> method to compare the * <code>Individual</code> equality. * * <p> * The given object can be an instance of <code>GraphVertex</code> or * <code>Individual</code>; Returns false otherwise. * </p> * * @param obj the reference object with which to compare equality * @return <code>true</code> if this node have the same * <code>Individual</code> as the object argumument; false * otherwise */ @Override public boolean equals(Object obj) { boolean res = false; if (obj instanceof GraphVertex) { res = (System.identityHashCode(individual) == System.identityHashCode(((GraphVertex) obj).getIndividual())); } else if (obj instanceof Individual) { res = (System.identityHashCode(individual) == System.identityHashCode((Individual) obj)); } return res; } @Override public GraphVertex clone() { try { GraphVertex clone = (GraphVertex) super.clone(); return clone; } catch (CloneNotSupportedException e) { throw new InternalError(); } } @Override public String toString() { String res = getClass().getSimpleName(); res += "["; res += "Generation#" + graphGeneration.getGeneration(); res += "@" + String.valueOf(System.identityHashCode(graphGeneration)); res += ","; res += "Individual@"; res += individual != null ? String.valueOf(System.identityHashCode(individual)) + ":" + individual.toString().substring(0, Math.min(10, individual.toString().length())) + "..." : "NULL"; res += ","; res += "Operator@"; res += operator != null ? String.valueOf(System.identityHashCode(operator)) + ":" + operator.getClass().getSimpleName() : "NULL"; res += ","; res += "Event@"; res += operatorEvent != null ? String.valueOf(System.identityHashCode(operatorEvent)) : "NULL"; if (operatorEvent != null) { res += ","; res += "Points:"; for (int i: operatorEvent.getPoints()) { res += i; res += " "; } } res += "]"; return res; } }