473 lines
16 KiB
Java
473 lines
16 KiB
Java
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);
|
||
}
|
||
}
|
||
}
|