#region License Information /* HeuristicLab * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views; using HeuristicLab.EvolutionTracking; namespace HeuristicLab.Problems.DataAnalysis.Symbolic { /// /// This class implements the bottom-up tree distance described in the following paper: /// G. Valiente, "An Efficient Bottom-up Distance Between Trees", http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.7958 /// public static class BottomUpDistanceCalculator { private static Dictionary Compact(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) { var G = new DirectedGraph(); var K = new Dictionary(); var F = new DisjointUnion(t1, t2); var L = new Dictionary(); var Children = new Dictionary(); var nodes = F.Nodes.ToList(); // for all leaf labels l in F foreach (var l in nodes.Where(x => x.SubtreeCount == 0)) { var label = Label(l); var z = new Vertex { Content = l, Label = label }; L[z.Label] = z; G.AddVertex(z); } var Q = new Queue(); // for all nodes foreach (var v in nodes) { Children[v] = v.SubtreeCount; if (v.SubtreeCount == 0) { Q.Enqueue(v); } } while (Q.Any()) { var v = Q.Dequeue(); if (v.SubtreeCount == 0) { K[v] = L[Label(v)]; // 18 } else { bool found = false; // for all nodes w in G in reverse order foreach (var w in G.Vertices.Reverse()) { if (Height(v) != Height(w) || v.SubtreeCount != w.OutDegree || Label(v) != w.Label) break; // sort V and W because we are dealing with unordered trees var V = v.Subtrees.Select(s => K[s]).OrderBy(x => x.Label); var W = w.OutArcs.Select(x => x.Target).OrderBy(x => x.Label); if (V.SequenceEqual(W)) { K[v] = w; found = true; break; } } // 32: end for if (!found) { var w = new Vertex { Content = v, Label = Label(v), Weight = Height(v) }; G.AddVertex(w); K[v] = w; foreach (var u in v.Subtrees) { G.AddArc(w, K[u]); } // 40: end for } // 41: end if } // 42: end if if (v.Parent != null) { var p = v.Parent; Children[p]--; if (Children[p] == 0) Q.Enqueue(p); } }; using (var file = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "graph.dot"))) { var str = G.ExportDot(); file.WriteLine(str); } return K; } private static Dictionary Mapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, Dictionary K) { var M = new Dictionary(); // nodes of t1 => nodes of t2 var M_ = new Dictionary(); // nodes of t2 => nodes of t1 var plist2 = t2.IterateNodesPrefix().ToList(); foreach (var n in t1.IterateNodesBreadth()) { ISymbolicExpressionTreeNode v = n; if (!M.ContainsKey(v)) { var w = plist2.Last(); var pw = plist2.IndexOf(w); // preorder index of node w foreach (var u in plist2.Where(x => K[x] == K[v])) { if (!M_.ContainsKey(u)) { w = u; // commented out test below since we are dealing with unordered trees // if (plist2.IndexOf(u) < pw) { // w = u; // } } } if (K[v] == K[w]) { // simultaneous preorder traversal of the two subtrees var nodesV = v.IterateNodesPrefix().ToList(); var nodesW = w.IterateNodesPrefix().ToList(); for (int i = 0; i < Math.Min(nodesV.Count, nodesW.Count); ++i) { var s = nodesV[i]; var t = nodesW[i]; M[s] = t; M_[t] = s; } } } } return M; } public static double CalculateDistance(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, double p = 1, double q = 1, double r = 1) { var K = Compact(t1, t2); var M = Mapping(t1, t2, K); int d = t1.Length - M.Count; int s = M.Count(x => !Label(x.Key).Equals(Label(x.Value))); int i = t2.Length - M.Count; double distance = s * p + i * q + d * r; if (distance / (t1.Length + t2.Length) > 0.5 && M.Count > 0) { using (var file = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "map.tex"))) { var str = FormatMapping(t1, t2, M); file.WriteLine(str); } } return distance; } private static string Label(ISymbolicExpressionTreeNode n) { return n.ToString(); } private static int Height(IVertex v) { return (int)Math.Round(v.Weight); // use the vertex weight as height in this particular context } private static int Height(ISymbolicExpressionTreeNode n) { var p = n; while (p.Parent != null) p = p.Parent; return p.GetBranchLevel(n); } private class DisjointUnion : Tuple { public DisjointUnion(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) : base(t1, t2) { } public IEnumerable Nodes { get { return Item1.Root.IterateNodesPostfix().Concat(Item2.Root.IterateNodesPostfix()); } } } // draw the mapping between t1 and t2 as a tikz picture private static string FormatMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, Dictionary map) { var formatter = new SymbolicExpressionTreeLatexFormatter(); var sb = new StringBuilder(); string s1, s2; var m1 = formatter.Format(t1, out s1); var m2 = formatter.Format(t2, out s2, 20); sb.Append(s1); sb.Append(s2); foreach (var p in map) { var id1 = m1[p.Key]; var id2 = m2[p.Value]; sb.Append(string.Format(CultureInfo.InvariantCulture, "\\path[draw,->] ({0}) edge[bend left,dashed] ({1});" + Environment.NewLine, id1, id2)); } return sb.ToString(); } } }