/// <summary> /// Compute the tree edit distance /// </summary> /// <returns>Returns a tuple. The first item is the cost. The second item is the /// sequence of edit operations</returns> public EditDistance Compute() { GenerateNodes(PreviousTree, CurrentTree); _l1 = ComputeL(T1, A); _l2 = ComputeL(T2, B); _k1 = ComputeK(T1, _l1); _k2 = ComputeK(T2, _l2); _treedists = new EditDistance[T1.Length + 1, T2.Length + 1]; _treedists[0, 0] = new EditDistance() { Distance = 0 }; foreach (var x in _k1) { foreach (var y in _k2) { Treedists(x, y); } } return(_treedists[T1.Length, T2.Length]); }
private void Treedists(int i, int j) { var m = i - _l1[i] + 2; var n = j - _l2[j] + 2; var fd = new EditDistance[m, n]; fd[0, 0] = new EditDistance() { Distance = 0 }; var ioff = _l1[i] - 1; var joff = _l2[j] - 1; for (int x = 1; x < m; x++) { var edits = new List <Edit>(fd[x - 1, 0].Edits); var pythonNode = A[x + ioff - 1]; edits.Add(new Delete(pythonNode, pythonNode.Parent)); fd[x, 0] = new EditDistance() { Distance = fd[x - 1, 0].Distance + 1, Edits = edits, Mapping = new Dictionary <PythonNode, PythonNode>(fd[x - 1, 0].Mapping) }; } for (int y = 1; y < n; y++) { var node = B[y - 1 + joff]; var edits = new List <Edit>(fd[0, y - 1].Edits); edits.Add(new Insert(node, node.Parent)); fd[0, y] = new EditDistance() { Distance = fd[0, y - 1].Distance + 1, Edits = edits, Mapping = new Dictionary <PythonNode, PythonNode>(fd[0, y - 1].Mapping) }; } for (int x = 1; x < m; x++) { for (int y = 1; y < n; y++) { if (_l1[i] == _l1[x + ioff] && _l2[j] == _l2[y + joff]) { var value = Math.Min(Math.Min(fd[x - 1, y].Distance + 1, //cost to remove is 1 fd[x, y - 1].Distance + 1), //cost to insert is 1 fd[x - 1, y - 1].Distance + CostUpdate(A[x + ioff - 1], B[y + joff - 1])); //cost to Edit depends List <Edit> edits; Dictionary <PythonNode, PythonNode> mapping; if (value == fd[x - 1, y].Distance + 1) { var node = A[x - 1 + ioff]; edits = new List <Edit>(fd[x - 1, y].Edits) { new Delete(node, node.Parent) }; mapping = new Dictionary <PythonNode, PythonNode>(fd[x - 1, y].Mapping); } else if (value == fd[x, y - 1].Distance + 1) { var node = B[y - 1 + joff]; edits = new List <Edit>(fd[x, y - 1].Edits) { new Insert(node, node.Parent) }; mapping = new Dictionary <PythonNode, PythonNode>(fd[x, y - 1].Mapping); } else { edits = new List <Edit>(fd[x - 1, y - 1].Edits); var oldNode = A[x + ioff - 1]; var newNode = B[y + joff - 1]; if (CostUpdate(oldNode, newNode) > 0) { edits.Add(new Update(newNode, oldNode)); } mapping = new Dictionary <PythonNode, PythonNode>(fd[x - 1, y - 1].Mapping); if (mapping.ContainsKey(newNode)) { mapping.Remove(newNode); } mapping.Add(newNode, oldNode); } fd[x, y] = new EditDistance() { Distance = value, Edits = edits, Mapping = mapping }; _treedists[x + ioff, y + joff] = fd[x, y]; } else { var p = _l1[x + ioff] - 1 - ioff; var q = _l2[y + joff] - 1 - joff; var value = Math.Min(fd[p, q].Distance + _treedists[x + ioff, y + joff].Distance, Math.Min(fd[x - 1, y].Distance + 1, fd[x, y - 1].Distance + 1)); List <Edit> edits; Dictionary <PythonNode, PythonNode> mapping; if (value == fd[p, q].Distance + _treedists[x + ioff, y + joff].Distance) { edits = new List <Edit>(fd[p, q].Edits); edits.AddRange(_treedists[x + ioff, y + joff].Edits); mapping = new Dictionary <PythonNode, PythonNode>(fd[p, q].Mapping); foreach (var keyValuePair in _treedists[x + ioff, y + joff].Mapping) { //todo there is problem a bug here //it should check whether the maps come from each one of them. if (mapping.ContainsKey(keyValuePair.Key)) { mapping.Remove(keyValuePair.Key); } PythonNode key = null; foreach (var keyValue in mapping) { if (keyValue.Value.Equals(keyValuePair.Value)) { key = keyValue.Key; } } if (key != null) { mapping.Remove(key); } mapping.Add(keyValuePair.Key, keyValuePair.Value); } } else if (value == fd[x - 1, y].Distance + 1) { edits = new List <Edit>(fd[x - 1, y].Edits); var pythonNode = A[x - 1 + ioff]; edits.Add(new Delete(pythonNode, pythonNode.Parent)); mapping = new Dictionary <PythonNode, PythonNode>(fd[x - 1, y].Mapping); } else { edits = new List <Edit>(fd[x, y - 1].Edits); var pythonNode = B[y - 1 + joff]; edits.Add(new Insert(pythonNode, pythonNode.Parent)); mapping = new Dictionary <PythonNode, PythonNode>(fd[x, y - 1].Mapping); } fd[x, y] = new EditDistance() { Distance = value, Edits = edits, Mapping = mapping }; } } } }