source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeDistance/BottomUpDistanceCalculator.cs @ 11015

Last change on this file since 11015 was 11015, checked in by bburlacu, 6 years ago

#1772: Added partially working implementation of a bottom-up distance calculator for symbolic expression trees. Changed latex formatter to also return a map of node ids (useful when wanting to display trees side by side).

File size: 7.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Globalization;
25using System.IO;
26using System.Linq;
27using System.Text;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
30using HeuristicLab.EvolutionTracking;
31
32namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
33  public static class BottomUpDistanceCalculator {
34    private static Dictionary<ISymbolicExpressionTreeNode, IVertex> Compact(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
35      var G = new DirectedGraph();
36      var K = new Dictionary<ISymbolicExpressionTreeNode, IVertex>();
37      var F = new DisjointUnion(t1, t2);
38      var Children = new Dictionary<ISymbolicExpressionTreeNode, int>();
39      var L = new Dictionary<string, IVertex>();
40      foreach (var l in F.Nodes.Where(x => x.SubtreeCount == 0)) {
41        var z = new Vertex { Content = l, Label = Label(l) };
42        z.Weight = Height(l); // might be necessary
43        L[z.Label] = z;
44        G.AddVertex(z);
45      }
46      var Q = new Queue<ISymbolicExpressionTreeNode>();
47      foreach (var v in F.Nodes) {
48        Children[v] = v.SubtreeCount;
49        if (v.SubtreeCount == 0) {
50          Q.Enqueue(v);
51        }
52      }
53      do {
54        var v = Q.Dequeue();
55        if (v.SubtreeCount == 0) {
56          K[v] = L[Label(v)]; // 18
57        } else {
58          bool found = false;
59
60          foreach (var w in G.Vertices.Reverse()) {
61            if (Height(v) != Height(w) || v.SubtreeCount != w.OutDegree || Label(v) != w.Label)
62              break;
63            // sort the lists before comparison, as required when dealing with unordered trees
64            var V = v.Subtrees.OrderBy(Label).Select(s => K[s]);
65            var W = w.OutArcs.Select(x => x.Target).OrderBy(x => x.Label);
66            if (V.SequenceEqual(W)) {
67              K[v] = w;
68              found = true;
69              break;
70            }
71          } // 32: end for
72
73          if (!found) {
74            var w = new Vertex { Content = v, Label = Label(v), Weight = Height(v) };
75            K[v] = w;
76
77            foreach (var u in v.Subtrees) {
78              G.AddArc(w, K[u]);
79            } // 40: end for
80          } // 41: end if
81        } // 42: end if
82
83        if (!F.IsRoot(v)) {
84          Children[v.Parent] = Children[v.Parent] - 1;
85          if (Children[v.Parent] == 0) {
86            Q.Enqueue(v.Parent);
87          } // 47: end if
88        } // 48: end if
89      } while (Q.Count != 0);
90      return K;
91    }
92
93    private static Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> Mapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, Dictionary<ISymbolicExpressionTreeNode, IVertex> K) {
94      var M = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t1 => nodes of t2
95      var M_ = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t2 => nodes of t1
96      //var plist1 = t1.IterateNodesPrefix().ToList();
97      var plist2 = t2.IterateNodesPrefix().ToList();
98      foreach (var v in t1.IterateNodesBreadth()) {
99        if (!M.ContainsKey(v)) {
100          var w = plist2.Last();
101          foreach (var u in plist2.Where(x => K[x] == K[v])) {
102            if (!M_.ContainsKey(u)) {
103              if (plist2.IndexOf(u) < plist2.IndexOf(w)) {
104                w = u;
105              }
106            }
107          }
108          if (K[v] == K[w]) {
109            // simultaneous preorder traversal of the two subtrees
110            var nodesV = v.IterateNodesPrefix().ToList();
111            var nodesW = w.IterateNodesPrefix().ToList();
112            for (int i = 0; i < Math.Min(nodesV.Count, nodesW.Count); ++i) {
113              var s = nodesV[i];
114              var t = nodesW[i];
115              M[s] = t;
116              M_[t] = s;
117            }
118            //            var e1 = v.IterateNodesPrefix().GetEnumerator();
119            //            var e2 = w.IterateNodesPrefix().GetEnumerator();
120            //            while (e1.MoveNext() && e2.MoveNext()) {
121            //              M[e1.Current] = e2.Current;
122            //              M_[e2.Current] = e1.Current;
123            //            }
124          }
125        }
126      }
127      return M;
128    }
129
130    public static double CalculateDistance(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, double p = 1, double q = 1, double r = 1) {
131      var K = Compact(t1, t2);
132      var M = Mapping(t1, t2, K);
133      int d = t1.Length - M.Count;
134      int s = M.Count(x => !Label(x.Key).Equals(Label(x.Value)));
135      int i = t2.Length - M.Count;
136
137      double distance = s * p + i * q + d * r;
138
139      if (distance / (t1.Length + t2.Length) > 0.5 && M.Count > 0) {
140        using (var file = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "map.txt"))) {
141          var str = FormatMapping(t1, t2, M);
142          file.WriteLine(str);
143        }
144      }
145
146      return distance;
147    }
148
149    private static string Label(ISymbolicExpressionTreeNode n) {
150      return n.ToString();
151    }
152
153    private static int Height(IVertex v) {
154      return (int)Math.Round(v.Weight); // use the vertex weight as height in this particular context
155    }
156
157    private static int Height(ISymbolicExpressionTreeNode n) {
158      var p = n;
159      while (p.Parent != null)
160        p = p.Parent;
161      return p.GetBranchLevel(n);
162    }
163
164    private class DisjointUnion : Tuple<ISymbolicExpressionTree, ISymbolicExpressionTree> {
165      public DisjointUnion(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2)
166        : base(t1, t2) {
167      }
168
169      public IEnumerable<ISymbolicExpressionTreeNode> Nodes {
170        get { return Item1.IterateNodesPrefix().Concat(Item2.IterateNodesPrefix()); }
171      }
172
173      public bool IsRoot(ISymbolicExpressionTreeNode n) {
174        return (n == Item1.Root || n == Item2.Root);
175      }
176    }
177
178    // draw the mapping between t1 and t2
179    private static string FormatMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> map) {
180      var formatter = new SymbolicExpressionTreeLatexFormatter();
181      var sb = new StringBuilder();
182
183      string s1, s2;
184      var m1 = formatter.Format(t1, out s1);
185      var m2 = formatter.Format(t2, out s2, 20);
186
187      sb.Append(s1);
188      sb.Append(s2);
189
190      foreach (var p in map) {
191        var id1 = m1[p.Key];
192        var id2 = m2[p.Value];
193
194        sb.Append(string.Format(CultureInfo.InvariantCulture, "\\path[draw,->] ({0}) edge[bend left,dashed] ({1});", id1, id2));
195      }
196
197      return sb.ToString();
198    }
199  }
200}
Note: See TracBrowser for help on using the repository browser.