eva2/src/eva2/optimization/individuals/GPIndividualProgramData.java
2013-10-12 13:49:50 +02:00

473 lines
16 KiB
Java
Raw Blame History

package eva2.optimization.individuals;
import eva2.optimization.individuals.codings.gp.AbstractGPNode;
import eva2.optimization.individuals.codings.gp.GPArea;
import eva2.optimization.individuals.codings.gp.InterfaceProgram;
import eva2.optimization.operator.crossover.CrossoverGPDefault;
import eva2.optimization.operator.mutation.InterfaceMutation;
import eva2.optimization.operator.mutation.MutateDefault;
import eva2.optimization.problems.InterfaceOptimizationProblem;
import eva2.tools.EVAERROR;
import eva2.tools.math.RNG;
import eva2.util.annotation.Description;
/**
* This individual uses a tree-based genotype to code for program trees.
*/
@Description(text = "This is a GP individual suited to optimize Koza style program trees.")
public class GPIndividualProgramData extends AbstractEAIndividual implements InterfaceGPIndividual, InterfaceDataTypeProgram, java.io.Serializable {
protected AbstractGPNode[] genotype;
protected AbstractGPNode[] phenotype;
protected GPArea[] gpArea;
protected double initFullGrowRatio = 0.5;
protected int initDepth = 4;
protected int maxAllowedDepth = 8;
protected boolean checkMaxDepth = true;
public GPIndividualProgramData() {
this.gpArea = new GPArea[1];
gpArea[0] = new GPArea();
this.genotype = new AbstractGPNode[1];
this.mutationOperator = new MutateDefault();
this.crossoverOperator = new CrossoverGPDefault();
}
public GPIndividualProgramData(GPIndividualProgramData individual) {
if (individual.phenotype != null) {
this.phenotype = new AbstractGPNode[individual.phenotype.length];
for (int i = 0; i < individual.phenotype.length; i++) {
if (individual.phenotype[i] != null) {
this.phenotype[i] = (AbstractGPNode) individual.phenotype[i].clone();
}
}
}
if (individual.genotype != null) {
this.genotype = new AbstractGPNode[individual.genotype.length];
this.gpArea = new GPArea[individual.gpArea.length];
for (int i = 0; i < individual.genotype.length; i++) {
if (individual.genotype[i] != null) {
this.genotype[i] = (AbstractGPNode) individual.genotype[i].clone();
this.genotype[i].connect(null);
}
if (individual.gpArea[i] != null) {
this.gpArea[i] = (GPArea) individual.gpArea[i].clone();
}
}
}
this.initFullGrowRatio = individual.initFullGrowRatio;
this.initDepth = individual.initDepth;
this.maxAllowedDepth = individual.maxAllowedDepth;
this.checkMaxDepth = individual.checkMaxDepth;
// cloning the members of AbstractEAIndividual
this.age = individual.age;
this.crossoverOperator = individual.crossoverOperator;
this.crossoverProbability = individual.crossoverProbability;
this.mutationOperator = (InterfaceMutation) individual.mutationOperator.clone();
this.mutationProbability = individual.mutationProbability;
this.selectionProbability = new double[individual.selectionProbability.length];
for (int i = 0; i < this.selectionProbability.length; i++) {
this.selectionProbability[i] = individual.selectionProbability[i];
}
this.fitness = new double[individual.fitness.length];
for (int i = 0; i < this.fitness.length; i++) {
this.fitness[i] = individual.fitness[i];
}
cloneAEAObjects((AbstractEAIndividual) individual);
}
@Override
public Object clone() {
return (Object) new GPIndividualProgramData(this);
}
/**
* This method checks on equality regarding genotypic equality
*
* @param individual The individual to compare to.
* @return boolean if equal true else false.
*/
@Override
public boolean equalGenotypes(AbstractEAIndividual individual) {
if (individual instanceof GPIndividualProgramData) {
GPIndividualProgramData indy = (GPIndividualProgramData) individual;
//@todo Eigendlich k<>nnte ich noch die Areas vergleichen
if (this.maxAllowedDepth != indy.maxAllowedDepth) {
return false;
}
if ((this.genotype == null) || (indy.genotype == null)) {
return false;
} else {
for (int i = 0; i < this.genotype.length; i++) {
if ((this.genotype[i] == null) || (indy.genotype[i] == null) || (!this.genotype[i].equals(indy.genotype[i]))) {
return false;
}
}
}
return true;
} else {
return false;
}
}
/************************************************************************************
* InterfaceDataTypeProgram methods
*/
/**
* This method allows you to request a certain amount of double data
*
* @param length The lenght of the double[] that is to be optimized
*/
@Override
public void setProgramDataLength(int length) {
GPArea[] oldArea = this.gpArea;
AbstractGPNode[] oldProg = this.genotype;
this.gpArea = new GPArea[length];
this.genotype = new AbstractGPNode[length];
for (int i = 0; ((i < this.gpArea.length) && (i < oldArea.length)); i++) {
this.gpArea[i] = oldArea[i];
this.genotype[i] = oldProg[i];
}
for (int i = oldArea.length; i < this.gpArea.length; i++) {
this.gpArea[i] = oldArea[oldArea.length - 1];
this.genotype[i] = oldProg[oldProg.length - 1];
}
}
/**
* This method allows you to read the program stored as Koza style node tree
*
* @return AbstractGPNode representing the binary data.
*/
@Override
public InterfaceProgram[] getProgramData() {
this.phenotype = new AbstractGPNode[this.genotype.length];
for (int i = 0; i < this.genotype.length; i++) {
this.phenotype[i] = (AbstractGPNode) this.genotype[i].clone();
// if (!phenotype[0].checkDepth(0)) {
// System.err.println("error... " + genotype[0].checkDepth(0));
// }
if ((this.checkMaxDepth) && (this.phenotype[i].isMaxDepthViolated(this.maxAllowedDepth))) {
System.err.println("Trying to meet the Target Depth! " + this.phenotype[i].isMaxDepthViolated(this.maxAllowedDepth) + " " + phenotype[i].getMaxDepth());
this.phenotype[i].repairMaxDepth(this.gpArea[i], this.maxAllowedDepth);
//System.out.println("TragetDepth: " + this.m_TargetDepth + " : " + this.m_Program.getMaxDepth());
}
}
return this.phenotype;
}
/**
* This method allows you to read the Program data without
* an update from the genotype
*
* @return InterfaceProgram[] representing the Program.
*/
@Override
public InterfaceProgram[] getProgramDataWithoutUpdate() {
if (this.phenotype == null) {
return getProgramData();
} else {
return this.phenotype;
}
}
/**
* This method allows you to set the program phenotype.
*
* @param program The new program.
*/
@Override
public void SetProgramPhenotype(InterfaceProgram[] program) {
if (program instanceof AbstractGPNode[]) {
this.phenotype = new AbstractGPNode[program.length];
for (int i = 0; i < this.phenotype.length; i++) {
this.phenotype[i] = (AbstractGPNode) ((AbstractGPNode) program[i]).clone();
}
}
}
/**
* This method allows you to set the program genotype.
*
* @param program The new program.
*/
@Override
public void SetProgramGenotype(InterfaceProgram[] program) {
this.SetProgramPhenotype(program);
if (program instanceof AbstractGPNode[]) {
this.genotype = new AbstractGPNode[program.length];
for (int i = 0; i < this.genotype.length; i++) {
this.genotype[i] = (AbstractGPNode) ((AbstractGPNode) program[i]).clone();
}
}
}
/**
* This method allows you to set the function area
*
* @param area The area contains functions and terminals
*/
@Override
public void SetFunctionArea(Object[] area) {
if (area instanceof GPArea[]) {
this.gpArea = (GPArea[]) area;
}
}
/**
* This method allows you to set the function area
*
* @return The function area
*/
@Override
public Object[] getFunctionArea() {
return this.gpArea;
}
/************************************************************************************
* InterfaceEAIndividual methods
*/
/**
* This method will init the individual with a given value for the
* phenotype.
*
* @param obj The initial value for the phenotype
* @param opt The optimization problem that is to be solved.
*/
@Override
public void initByValue(Object obj, InterfaceOptimizationProblem opt) {
if (obj instanceof InterfaceProgram[]) {
this.SetProgramGenotype((InterfaceProgram[]) obj);
} else {
this.defaultInit(opt);
System.out.println("Initial value for GPIndividualDoubleData is no InterfaceProgram[]!");
}
this.mutationOperator.init(this, opt);
this.crossoverOperator.init(this, opt);
}
/**
* This method will return a string description of the GAIndividal
* noteably the Genotype.
*
* @return A descriptive string
*/
@Override
public String getStringRepresentation() {
String result = "";
result += "GPIndividual coding program: (";
result += "Fitness {";
for (int i = 0; i < this.fitness.length; i++) {
result += this.fitness[i] + ";";
}
result += "}/SelProb{";
for (int i = 0; i < this.selectionProbability.length; i++) {
result += this.selectionProbability[i] + ";";
}
result += "})\n Value: ";
for (int i = 0; i < this.genotype.length; i++) {
if (this.genotype[i] != null) {
result += this.genotype[i].getStringRepresentation();
}
result += "\nUsing " + this.genotype[i].getNumberOfNodes() + " nodes.";
}
return result;
}
/************************************************************************************
* InterfaceGPIndividual methods
*/
/**
* This method will allow the user to read the program genotype
*
* @return AbstractGPNode
*/
@Override
public AbstractGPNode[] getPGenotype() {
return this.genotype;
}
/**
* This method will allow the user to set the current program 'genotype'.
*
* @param b The new programgenotype of the Individual
*/
@Override
public void setPGenotype(AbstractGPNode[] b) {
this.genotype = b;
this.phenotype = null;
}
/**
* This method will allow the user to set the current program 'genotype'.
*
* @param b The new program genotype of the Individual
* @param i The index where to insert the new program
*/
@Override
public void setPGenotype(AbstractGPNode b, int i) {
this.genotype[i] = b;
genotype[i].updateDepth(0);
// System.out.println("Setting pheno of depth " + b.getMaxDepth() + " " + b.getStringRepresentation());
this.phenotype = null;
}
/**
* This method performs a simple one element mutation on the program
*/
@Override
public void defaultMutate() {
for (int i = 0; i < this.genotype.length; i++) {
AbstractGPNode nodeToMutate = this.genotype[i].getRandomNode();
if (nodeToMutate.getParent() == null) { // mutate at root
this.defaultInit(null);
} else {
AbstractGPNode parent = nodeToMutate.getParent();
if (checkMaxDepth && (nodeToMutate.getDepth() == maxAllowedDepth)) { // mutate with a constant
AbstractGPNode newNode = (AbstractGPNode) (((AbstractGPNode) this.gpArea[i].getRandomNodeWithArity(0).clone()));
newNode.setDepth(nodeToMutate.getDepth());
parent.setNode(newNode, nodeToMutate);
} else {
AbstractGPNode newNode = (AbstractGPNode) (((AbstractGPNode) this.gpArea[i].getRandomNode().clone()));
newNode.setDepth(nodeToMutate.getDepth());
newNode.initGrow(this.gpArea[i], this.maxAllowedDepth);
parent.setNode(newNode, nodeToMutate);
}
//if (!genotype[i].checkDepth(0) || (genotype[i].isMaxDepthViolated(maxAllowedDepth))) {
// System.err.println("Error in GPIndividualProgramData.defaultMutate!");
//}
}
}
phenotype = null; // reset pheno
}
@Override
public void defaultInit(InterfaceOptimizationProblem prob) {
phenotype = null; // reset pheno
for (int i = 0; i < this.gpArea.length; i++) {
if (this.gpArea[i] == null) {
EVAERROR.errorMsgOnce("Error in GPIndividualProgramData.defaultInit(): Area[" + i + "] == null !!");
} else {
this.genotype[i] = (AbstractGPNode) (this.gpArea[i].getRandomNonTerminal()).clone();
this.genotype[i].setDepth(0);
int targetDepth = RNG.randomInt(1, this.initDepth);
if (RNG.flipCoin(this.initFullGrowRatio)) {
this.genotype[i].initFull(this.gpArea[i], targetDepth);
} else {
this.genotype[i].initGrow(this.gpArea[i], targetDepth);
}
}
}
}
/**
* This method allows the CommonJavaObjectEditorPanel to read the
* name to the current object.
*
* @return The name.
*/
@Override
public String getName() {
return "GP individual";
}
/**
* This method will toggle between checking for max depth or not.
*
* @param b the Switch.
*/
public void setCheckMaxDepth(boolean b) {
this.checkMaxDepth = b;
}
public boolean getCheckMaxDepth() {
return this.checkMaxDepth;
}
public String checkMaxDepthTipText() {
return "If activated the maximum depth of the program tree will be enforced.";
}
/**
* This method set/get the init Full Grow Ratio.
*
* @param b The new init Full Grow Ratio of the GP Tree.
*/
public void setInitFullGrowRatio(double b) {
if (b < 0) {
b = 0;
}
if (b > 1) {
b = 1;
}
this.initFullGrowRatio = b;
}
public double getInitFullGrowRatio() {
return this.initFullGrowRatio;
}
public String initFullGrowRatioTipText() {
return "The ratio between the full and the grow init methods (1 uses only full initializing).";
}
/**
* This method set/get the init depth.
*
* @param b The new init Depth of the GP Tree.
*/
public void setInitDepth(int b) {
if (b > this.maxAllowedDepth) {
System.out.println("Waring Init Depth will be set to Target Depth!");
b = this.maxAllowedDepth;
}
this.initDepth = b;
}
public int getInitDepth() {
return this.initDepth;
}
public String initDepthTipText() {
return "The initial depth of the GP Tree.";
}
/**
* This method set/get the target depth.
*
* @param b The new target Depth of the GP Tree.
*/
public void setMaxAllowedDepth(int b) {
this.maxAllowedDepth = b;
}
@Override
public int getMaxAllowedDepth() {
return this.maxAllowedDepth;
}
public String maxAllowedDepthTipText() {
return "The maximum depth allowed for the GP tree.";
}
public String[] customPropertyOrder() {
return new String[]{"initDepth", "checkMaxDepth", "maxAllowedDepth"};
}
public void updateDepth() {
for (int i = 0; i < genotype.length; i++) {
genotype[i].updateDepth(0);
}
}
public void checkDepth() {
for (int i = 0; i < genotype.length; i++) {
genotype[i].checkDepth(0);
}
}
}