交叉中的子树替换

时间:2015-09-01 09:50:35

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

我对有关遗传编程的学校项目有疑问。

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

  1. 从父树中选择一个随机节点(插入点)。
  2. 从母树中选择一个随机子树。
  3. 用父亲的子树替换父亲的插入点。
  4. 我很确定第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

1 个答案:

答案 0 :(得分:0)

对于你的学校项目来说,这可能为时已晚,但如果它可以帮助任何有类似问题的人发布答案:

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

相关问题