def create_mapping(root1, root2): """Creates mapping between trees rooted at root1 and root2 Returns: -- new root -- map from node index 1 to resulting node -- map from node index 2 to resulting node """ apted = APTED(root1, root2, CONFIG) mapping = apted.compute_edit_mapping() combined_duration = copy(root1.duration) combined_duration.update(root2.duration) trial_ids = root1.trial_ids + root2.trial_ids id_to_node1 = {} id_to_node2 = {} for node1, node2 in mapping: if node1 is None: node = id_to_node2[node2.index] = copy(node2) node.children1 = [] node.children2 = node2.children node.original1 = None node.original2 = node2.index elif node2 is None: node = id_to_node1[node1.index] = copy(node1) node.children1 = node1.children node.children2 = [] node.original1 = node1.index node.original2 = None else: if node1.name != node2.name: print("Warning. Mismatch?", node1.name, node2.name) merge(node1, node2, id_to_node1, id_to_node2) # Note that it overrides node1 attributes if id_to_node1[root1.index] is not id_to_node2[root2.index]: root = Node( index=0, parent_index=0, name="<diff>", caller_id=0, original1=None, original2=None, children1=[root1], children2=[root2], activations=[], duration=combined_duration, full_tooltip=True, tooltip={x: "Diff" for x in trial_ids}, children_index=-1, trial_ids=trial_ids ) else: root = id_to_node1[root1.index] return root, id_to_node1, id_to_node2
def diff(tree_before: Node, tree_after: Node) -> (int, dict): """ Returns the difference between two QEP trees :param tree_before: The 'before tree'. :param tree_after: The 'after tree'. :return: distance: The structural edit distance between the two trees. Only difference in algorithm is captured. delta: The difference between the two trees. Has 3 keys: - deleted: Those nodes that are deleted from tree_before - inserted: Those nodes that are inserted into tree_after - stayed: Those nodes that are present in both trees. Has two keys: - before: the nodes in tree_before - after : the nodes in tree_after Note that the before and after may be different in attributes other than algorithm and operation. """ apted = APTED(tree_before, tree_after, APTEDConfig()) distance = apted.compute_edit_distance() mapping = apted.compute_edit_mapping() delta = { "deleted": [m[0] for m in mapping if m[1] is None], "inserted": [m[1] for m in mapping if m[0] is None], "stayed": { "before": [m[0] for m in mapping if m[0] is not None and m[1] is not None], "after": [m[1] for m in mapping if m[0] is not None and m[1] is not None] } } return distance, delta