【问题标题】:Subtree replacement in crossover交叉中的子树替换
【发布时间】:2015-09-01 09:50:35
【问题描述】:

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

我正在使用子树交叉方法,所以我必须执行这些步骤:

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

我很确定第三点在我的代码中不起作用。我已经尝试了几种不同的方法来解决这个问题(Deep copying and swapping subtrees in java - 这个也是),但它们似乎都不起作用。

我认为可行的方法是创建一个名为“child”的新树,它是父树的副本,然后使用该树找到一个随机节点,然后将找到的节点替换为子树(所以实际上也是一个节点)来自母树。

我还尝试在树中搜索匹配项,明确更新父母/孩子,但一切都表明这不是解决方案,或者我做错了。

所以我给你我的代码的基本版本;非常感谢我的思维方式有问题的每一个提示。

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

【问题讨论】:

    标签: java tree binary-tree genetic-programming crossover


    【解决方案1】:

    对于您的学校项目来说,这可能为时已晚,但发布答案以防遇到类似问题的人有所帮助:

    问题出在 CrossOver 方法中:“子”变量作为“父”模式的副本开始。然后,创建指向要替换的子树的变量“insertionPoint”。但是,当您将“motherSubtree”分配给该变量时,您实际上只是替换了方法中的本地变量,而不是对象中的子树。您实际上需要在新树创建后“重新插入”“motherSubtree”的副本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-22
      • 2021-03-20
      • 1970-01-01
      • 2015-05-11
      • 1970-01-01
      相关资源
      最近更新 更多