繁体   English   中英

交叉中的子树替换

[英]Subtree replacement in crossover

我有一个关于基因编程的学校项目有问题。

我正在使用子树交叉方法,因此我必须执行以下步骤:

  1. 从父树中选择一个随机节点(插入点)。
  2. 从母树中选择一个随机子树。
  3. 将父亲的插入点替换为母亲的子树。

我很确定第三点在我的代码中不起作用。 我已经尝试了几种解决此问题的方法( 在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM