[英]Subtree replacement in crossover
我有一个关于基因编程的学校项目有问题。
我正在使用子树交叉方法,因此我必须执行以下步骤:
我很确定第三点在我的代码中不起作用。 我已经尝试了几种解决此问题的方法( 在Java中进行深度复制和交换子树 -这也是),但它们似乎都不起作用。
他们以为我认为可行的方式是创建一个新树,称为“子”,将其作为父树的副本,然后使用该树找到一个随机节点,然后将所找到的节点替换为子树(因此实际上节点))。
我还尝试过在树上寻找匹配项,显式更新了父母/孩子,但所有内容都表明,这不是解决方案,就是我做错了。
因此,我为您提供了代码的基本版本; 我对我的思维方式出了什么问题的所有暗示都深表感谢。
TreeNode.java
public class TreeNode implements Iterable<TreeNode> {
protected Data data;
protected TreeNode parent;
protected List<TreeNode> children;
public static Long IDENTIFIER = 0L;
public double getValue(double xValue) {
return 0;
};
public boolean isRoot() {
return parent == null;
}
public boolean isLeaf() {
return children.size() == 0;
}
protected List<TreeNode> elementsIndex;
public TreeNode(Data data) {
this.data = data;
this.children = new LinkedList<TreeNode>();
this.elementsIndex = new LinkedList<TreeNode>();
this.elementsIndex.add(this);
this.data.setId(IDENTIFIER++);
if (this instanceof Function)
this.data.setChildAmount(2);
else if (this instanceof Terminal)
this.data.setChildAmount(0);
}
public TreeNode(Data data, TreeNode parent) {
this.parent = parent;
this.children = new LinkedList<TreeNode>();
this.elementsIndex = new LinkedList<TreeNode>();
this.elementsIndex.add(this);
this.data.setId(IDENTIFIER++);
if(this instanceof Function)
this.data.setChildAmount(2);
else if (this instanceof Terminal)
this.data.setChildAmount(0);
}
public TreeNode copyTree() {
TreeNode clone;
switch (this.getData().getType()) {
case 10:
clone = new Add(new Data(10));
break;
case 11:
clone = new Substract(new Data(11));
break;
case 12:
clone = new Multiply(new Data(12));
break;
case 13:
clone = new Divide(new Data(13));
break;
case 20:
clone = new Constant(new Data(20));
break;
case 21:
clone = new Variable(new Data(21));
break;
default:
return null;
}
clone.setData(this.getData());
clone.setParent(this.getParent());
clone.setChildren(this.getChildren());
clone.setElementsIndex(this.getElementsIndex());
return clone;
}
public TreeNode copy() {
return copyWithParent(parent);
}
public TreeNode copyWithParent(TreeNode parent) {
TreeNode out;
switch (this.getData().getType()) {
case 10:
out = new Add(new Data(10), parent);
break;
case 11:
out = new Substract(new Data(11), parent);
break;
case 12:
out = new Multiply(new Data(12), parent);
break;
case 13:
out = new Divide(new Data(13), parent);
break;
case 20:
out = new Constant(new Data(20), parent);
break;
case 21:
out = new Variable(new Data(21), parent);
break;
default:
return null;
}
if (!this.getChildren().isEmpty()) {
if (this.getChildren().get(0) != null) {
out.getChildren().get(0).copyWithParent(out);
}
if (this.getChildren().get(1) != null) {
out.getChildren().get(1).copyWithParent(out);
}
}
return out;
}
public TreeNode addChild(Data childType, TreeNode child) {
TreeNode childNode = child.copyTree();
childNode.parent = this;
this.children.add(childNode);
this.registerChildForSearch(childNode);
return childNode;
}
public int getLevel() {
if (this.isRoot())
return 0;
else
return parent.getLevel() + 1;
}
private TreeNode selectSubClass(Data data) {
switch (data.getType()) {
case 10:
return new Add(data);
case 11:
return new Substract(data);
case 12:
return new Multiply(data);
case 13:
return new Divide(data);
case 20:
return new Constant(data);
case 21:
return new Variable(data);
default:
return null;
}
}
private void registerChildForSearch(TreeNode node) {
elementsIndex.add(node);
if (parent != null)
parent.registerChildForSearch(node);
}
public TreeNode findTreeNode(Comparable<Data> cmp) {
for (TreeNode element : this.elementsIndex) {
Data elData = element.data;
if (cmp.compareTo(elData) == 0)
return element;
}
return null;
}
@Override
public String toString() {
return ((data != null) ? this.getData().toString() : "[null]");
}
public String printFunction() {
String left;
String right;
if (!this.getChildren().isEmpty()) {
left = this.getChildren().get(0).printFunction();
right = this.getChildren().get(1).printFunction();
return "(" + left + ")" + this.getData().toString() + "(" + right + ")";
}
return this.getData().toString();
}
@Override
public Iterator<TreeNode> iterator() {
TreeNodeIter iter = new TreeNodeIter(this);
return iter;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public TreeNode getParent() {
return parent;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
public List<TreeNode> getChildren() {
return children;
}
public void setChildren(List<TreeNode> children) {
this.children.addAll(children);
}
public List<TreeNode> getElementsIndex() {
return elementsIndex;
}
public void setElementsIndex(List<TreeNode> elementsIndex) {
this.elementsIndex = elementsIndex;
}
// Ghost Method - should be always overriden
public TreeNode chooseRandomChild() {
return null;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TreeNode other = (TreeNode) obj;
if (children == null) {
if (other.children != null)
return false;
} else if (!children.equals(other.children))
return false;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
if (elementsIndex == null) {
if (other.elementsIndex != null)
return false;
} else if (!elementsIndex.equals(other.elementsIndex))
return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
return true;
}
}
来自Chromosome.java的二手方法
public TreeNode chooseRandomNode(TreeNode remainingSubtree, boolean isInitial, int chosenMaxLevel,
int currentLevel) {
int maxLevel = 0;
TreeNode chosenNode = remainingSubtree.getParent();
if (isInitial) {
// if method was called on tree with single node
if (remainingSubtree instanceof Terminal)
return remainingSubtree;
this.treeHeight = countTreeDepth(this.getSchema());
Random random = new Random();
maxLevel = random.nextInt(treeHeight) + 1;
} else {
maxLevel = chosenMaxLevel;
}
if (currentLevel < maxLevel) {
TreeNode temp = remainingSubtree.chooseRandomChild();
if (temp instanceof Function)
chosenNode = chooseRandomNode(temp, false, maxLevel, currentLevel + 1);
else
chosenNode = temp;
}
return chosenNode;
}
public int countTreeDepth(TreeNode node) {
if (node.equals(null)) {
return 0;
}
if (!node.getChildren().isEmpty()) {
int leftChild = countTreeDepth(node.getChildren().get(0));
int rightChild = countTreeDepth(node.getChildren().get(1));
return (leftChild > rightChild) ? leftChild + 1 : rightChild + 1;
}
return 1;
}
Genetics.java中的交叉方法
public static Chromosome crossover(Chromosome father, Chromosome mother) {
TreeNode child = father.getSchema();
TreeNode insertionPoint = father.chooseRandomNode(child, true, 0, 0);
TreeNode temp = insertionPoint.copy();
TreeNode motherSubTree = mother.chooseRandomNode(mother.getSchema(), true, 0, 0);
insertionPoint = motherSubTree.copyTree();
Chromosome offspring = new Chromosome();
offspring.copyIndividual(child);
return offspring;
}
这是整个项目的GitHub存储库链接: https : //github.com/Nevaan/symbolic_regression
对于您的学校项目来说,这可能为时已晚,但请发布答案以防万一有类似问题的人得到帮助:
问题出在CrossOver方法中:“子”变量以“父”模式的副本开始。 然后,创建指向要替换的子树的变量“ insertionPoint”。 但是,当您将“ motherSubtree”分配给该变量时,实际上您只是在替换方法中的局部变量,而不是对象中的子树。 创建新树后,实际上您实际上需要将“ motherSubtree”的副本“重新插入”到新树中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.