Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/QueryMatch.cs @ 12951

Last change on this file since 12951 was 12951, checked in by bburlacu, 9 years ago

#1772:

  • Slight refactor in QueryMatch.cs
  • Added a parameter to the genealogy analyzer for removing older generations from the graph (useful to conserve memory in experiments)
  • Updated wildcard nodes (added persistence & cloning)
  • Implemented diversification strategy based on schema frequencies & phenotypic similarity as a separate operator (for now keep also the analyzer)
  • Updated license headers
  • Added QueryMatch performance test (to be expanded)
File size: 7.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Collections.Generic;
23using System.Linq;
24using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
25
26namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
27  // this class implements the decision version of the tree pattern query matching algorithm
28  // by M. Götz, C. Koch and W. Martens in http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.182.5440
29  public class QueryMatch {
30    private List<NodeInfo> dNodes;
31    private List<NodeInfo> qNodes;
32    private readonly ISymbolicExpressionTreeNodeEqualityComparer comparer;
33
34    private QueryMatch() { }
35
36    // whether matching nodes should also have matching parents
37    // in theory, this restricts the matching so that parent-child
38    // pairs in the query tree are matched by parent-child pairs in
39    // the data tree (and not ancestor-descendant pairs)
40    public bool MatchParents { get; set; }
41
42    public QueryMatch(ISymbolicExpressionTreeNodeEqualityComparer comparer) {
43      this.comparer = comparer;
44    }
45
46    public bool Match(ISymbolicExpressionTree data, ISymbolicExpressionTree query) {
47      return Match(data.Root.GetSubtree(0).GetSubtree(0), query.Root.GetSubtree(0).GetSubtree(0));
48    }
49
50    public bool Match(ISymbolicExpressionTreeNode data, ISymbolicExpressionTreeNode query) {
51      if (!comparer.Equals(data, query))
52        return false;
53
54      dNodes = InitializePostOrder(data);
55      qNodes = InitializePostOrder(query);
56
57      var dRoot = dNodes.Last();
58      var qRoot = qNodes.Last();
59      var result = Tmatch(dRoot, qNodes.First(), qNodes.Last());
60      return result == qRoot;
61    }
62
63    private bool AreMatching(NodeInfo a, NodeInfo b) {
64      // force the nodes to be on the same level
65      if (a.Level != b.Level)
66        return false;
67
68      bool equals = comparer.Equals(a.Node, b.Node);
69
70      if (equals && MatchParents) {
71        var pa = a.Parent;
72        var pb = b.Parent;
73        if (pa == null && pb == null)
74          return true;
75        if (pa != null && pb != null)
76          return pa.Level == pb.Level && comparer.Equals(pa.Node, pb.Node);
77        return false;
78      }
79      return equals;
80    }
81
82    private NodeInfo Tmatch(NodeInfo d, NodeInfo qFrom, NodeInfo qUntil) {
83      NodeInfo qBest = d.IsLeaf ? qFrom.Previous : Hmatch(d.LastChild, qFrom, qUntil);
84      var next = qBest.Next;
85      if (next.Index <= qUntil.Index && AreMatching(d, next)) {
86        qBest = next;
87        next = qBest.Next;
88        var lastSibling = qBest.LastSibling;
89        return next.Index <= lastSibling.Index ? Tmatch(d, next, lastSibling) : qBest;
90      }
91      return qBest;
92    }
93
94    private NodeInfo Hmatch(NodeInfo d, NodeInfo qFrom, NodeInfo qUntil) {
95      if (d.IsFirstSibling)
96        return Tmatch(d, qFrom, qUntil);
97
98      var qHedge = Hmatch(d.PreviousSibling, qFrom, qUntil);
99      var qTree = Tmatch(d, qFrom, qUntil);
100
101      for (;;) {
102        if (qHedge == qTree)
103          return qHedge;
104        if (qTree.Index < qHedge.Index) {
105          var rtop = Rtop(qTree.Next, qHedge);
106          while (rtop.Index < int.MaxValue && qHedge.Index < rtop.LastSibling.Index) {
107            qTree = Tmatch(d, rtop.Next, rtop.LastSibling);
108            rtop = Rtop(qTree.Next, qHedge);
109          }
110          if (qTree.Index <= qHedge.Index)
111            return qHedge;
112        } else {
113          var rtop = Rtop(qHedge.Next, qTree);
114          while (rtop.Index < int.MaxValue && qTree.Index < rtop.LastSibling.Index) {
115            qHedge = Hmatch(d.PreviousSibling, rtop.Next, rtop.LastSibling);
116            rtop = Rtop(qHedge.Next, qTree);
117          }
118          if (qHedge.Index <= qTree.Index)
119            return qTree;
120        }
121      }
122    }
123
124    // returns the rightmost node from the topmost nodes in the interval [hFrom, hUntil]
125    private NodeInfo Rtop(NodeInfo hFrom, NodeInfo hUntil) {
126      if (hFrom == hUntil)
127        return hUntil;
128      if (hFrom.Index > hUntil.Index)
129        return new NodeInfo { Node = null, Index = int.MaxValue };
130      // let u be the highest ancestor of hUntil that has a previous sibling s such that s >= hFrom
131      // if no such u exists, then Rtop(hFrom, hUntil) = hUntil. Otherwise, rtop(hFrom, hUntil) = s
132      NodeInfo rtop = null;
133      List<NodeInfo> ancestors = hUntil.Ancestors.ToList();
134      // ancestors list is ordered in decreasing depth therefore we start from the end
135      for (int i = ancestors.Count - 1; i >= 0; --i) {
136        if (ancestors[i].Parent == null || ancestors[i].IsFirstSibling)
137          continue;
138        var s = ancestors[i].PreviousSibling;
139        if (s != null && s.Index >= hFrom.Index) {
140          rtop = s;
141          break;
142        }
143      }
144      return rtop ?? hUntil;
145    }
146
147    private List<NodeInfo> InitializePostOrder(ISymbolicExpressionTreeNode node) {
148      var list = node.IterateNodesPostfix().ToList();
149      var nodes = list.Select((x, i) => new NodeInfo { Node = x, Index = i, Level = node.GetBranchLevel(x) }).ToList();
150      var map = Enumerable.Range(0, list.Count).ToDictionary(i => list[i], i => nodes[i]);
151
152      var inf = new NodeInfo { Node = null, Index = int.MaxValue, Previous = nodes.Last() };
153      var nil = new NodeInfo { Node = null, Index = -1, Next = nodes.First() };
154
155      foreach (var n in nodes) {
156        n.Parent = n.Node.Parent != null && map.ContainsKey(n.Node.Parent) ? map[n.Node.Parent] : null;
157        n.Next = n == nodes.Last() ? inf : nodes[n.Index + 1];
158        n.Previous = n == nodes.First() ? nil : nodes[n.Index - 1];
159        if (n.Parent == null) {
160          n.PreviousSibling = n.NextSibling = null;
161          n.LastSibling = nil;
162        } else {
163          var parent = n.Parent.Node;
164          int si = parent.IndexOfSubtree(n.Node);
165          n.PreviousSibling = n.IsFirstSibling ? null : map[parent.GetSubtree(si - 1)];
166          n.NextSibling = n.IsLastSibling ? null : map[parent.GetSubtree(si + 1)];
167          n.LastSibling = map[parent.Subtrees.Last()];
168        }
169        n.LastChild = n.IsLeaf ? null : n.Previous;
170      }
171      return nodes;
172    }
173
174    private class NodeInfo {
175      public ISymbolicExpressionTreeNode Node { get; set; }
176      public int Index { get; set; }
177      public int Level { get; set; }
178      public NodeInfo Parent { get; set; }
179      public NodeInfo Previous { get; set; }
180      public NodeInfo PreviousSibling { get; set; }
181      public NodeInfo Next { get; set; }
182      public NodeInfo NextSibling { get; set; }
183      public NodeInfo LastSibling { get; set; }
184      public NodeInfo LastChild { get; set; }
185
186      public bool IsLeaf {
187        get { return Node.SubtreeCount == 0; }
188      }
189
190      public bool IsFirstSibling {
191        get { return Node.Parent != null && Node == Node.Parent.Subtrees.First(); }
192      }
193
194      public bool IsLastSibling {
195        get { return Node.Parent != null && Node == Node.Parent.Subtrees.Last(); }
196      }
197
198      public IEnumerable<NodeInfo> Ancestors {
199        get {
200          var p = Parent;
201          while (p != null) {
202            yield return p;
203            p = p.Parent;
204          }
205        }
206      }
207    }
208  }
209}
210
Note: See TracBrowser for help on using the repository browser.