From 1c7f6f458fcc8458f0347d1c35525726183cfe97 Mon Sep 17 00:00:00 2001 From: cgarcia-UCO <42171969+cgarcia-UCO@users.noreply.github.com> Date: Tue, 18 Oct 2022 00:36:02 +0200 Subject: [PATCH] Exchanging the actual subtrees (crossover.subtree) # The problem crossover.subtree.do_crossover looked for the exchanging subtrees by means of method index (lines 279, 293, 307, and 308). However, the instruction pX.children.index(tX) returned the index of the subtree with the same content (I suppose that for which Tree.__eq__ returns True), but perhaps that is not the right subtree. ## Example: p0.children = ['whatever_1', 'Yes', 'whatever_2', 'Yes'] t0 = p0.children[3] # i.e. str(0) == 'Yes' p0.children.index(t0) # this returns 1, but the actual index of t0 is 3 # Implications Since the trees are not exchanging the right subtrees, the new trees share nodes. But not nodes with the same content, but actually the same objects in memory. The problem is that subsequent modification in Tree A may produce modifications in another expected independent Tree B, because they share the same node-objects. # Final comment I am not sure if this is significant in other problems (/ grammars / linear operators / ...). It was in my case, since I am using some operators for prunning the trees in the context of classification with decision trees (a grammar similar to the if_else_classifier.bnf). In particular, due to the interaction between my prunning operators and the aforementioned fact, I was getting some trees that did not point to their parents, which actually contained them in property children, and viceversa, some trees pointing to parent nodes that did not contained them in property children. In case it was interesting, I noticed that Tree B changed when changing A, afterwards I noticed that there were trees sharing the same objects, and finally, I detected that behaviour in the method index. Best regards. --- src/operators/crossover.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/operators/crossover.py b/src/operators/crossover.py index f317bcf1..f29eabeb 100755 --- a/src/operators/crossover.py +++ b/src/operators/crossover.py @@ -276,7 +276,7 @@ def do_crossover(tree0, tree1, shared_nodes): tree0 = t1 # Swap over the subtrees between parents. - i1 = p1.children.index(t1) + i1 = [id(i) for i in p1.children].index(id(t1)) p1.children[i1] = t0 # Set the parents of the crossed-over subtrees as their new @@ -290,7 +290,7 @@ def do_crossover(tree0, tree1, shared_nodes): tree1 = t0 # Swap over the subtrees between parents. - i0 = p0.children.index(t0) + i0 = [id(i) for i in p0.children].index(id(t0)) p0.children[i0] = t1 # Set the parents of the crossed-over subtrees as their new @@ -304,8 +304,8 @@ def do_crossover(tree0, tree1, shared_nodes): # For the parent nodes of the original subtrees, get the indexes # of the original subtrees. - i0 = p0.children.index(t0) - i1 = p1.children.index(t1) + i0 = [id(i) for i in p0.children].index(id(t0)) + i1 = [id(i) for i in p1.children].index(id(t1)) # Swap over the subtrees between parents. p0.children[i0] = t1