1 | using System.Collections.Generic;
|
---|
2 | using System.Linq;
|
---|
3 | using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
|
---|
4 |
|
---|
5 | namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
|
---|
6 | public class SymbolicExpressionTreeNodeSimilarityComparer : IEqualityComparer<ISymbolicExpressionTreeNode> {
|
---|
7 |
|
---|
8 | public SymbolicExpressionTreeNodeSimilarityComparer(int similarityLevel) {
|
---|
9 | _similarityLevel = similarityLevel;
|
---|
10 | }
|
---|
11 |
|
---|
12 | public int GetHashCode(ISymbolicExpressionTreeNode n) {
|
---|
13 | return n.ToString().ToLower().GetHashCode();
|
---|
14 | }
|
---|
15 |
|
---|
16 | public bool Equals(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
|
---|
17 | if (a.SubtreeCount != b.SubtreeCount) { return false; }
|
---|
18 | if (a.SubtreeCount > 0) { return a.Symbol.ToString().Equals(b.Symbol.ToString()); }
|
---|
19 | // compare leaf nodes according to desired similarity level
|
---|
20 | switch (_similarityLevel) {
|
---|
21 | case ((int)SymbolicExpressionTreeMatching.SimilarityLevel.Exact):
|
---|
22 | if (a is ConstantTreeNode && b is ConstantTreeNode) {
|
---|
23 | return ((ConstantTreeNode)a).Value.Equals(((ConstantTreeNode)b).Value);
|
---|
24 | }
|
---|
25 | if (a is VariableTreeNode && b is VariableTreeNode) {
|
---|
26 | return (a as VariableTreeNode).Weight.Equals((b as VariableTreeNode).Weight);
|
---|
27 | }
|
---|
28 | return false;
|
---|
29 |
|
---|
30 | case ((int)SymbolicExpressionTreeMatching.SimilarityLevel.High):
|
---|
31 | return (a is ConstantTreeNode && b is ConstantTreeNode) || (a is VariableTreeNode && b is VariableTreeNode);
|
---|
32 |
|
---|
33 | case ((int)SymbolicExpressionTreeMatching.SimilarityLevel.Relaxed):
|
---|
34 | return true;
|
---|
35 |
|
---|
36 | default:
|
---|
37 | return false;
|
---|
38 | }
|
---|
39 | }
|
---|
40 |
|
---|
41 | private readonly int _similarityLevel;
|
---|
42 | }
|
---|
43 |
|
---|
44 | public class SymbolicExpressionTreeNodeOrderingComparer : IComparer<ISymbolicExpressionTreeNode> {
|
---|
45 | public int Compare(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
|
---|
46 | if (a is ConstantTreeNode) {
|
---|
47 | if (b is ConstantTreeNode)
|
---|
48 | return a.Symbol.ToString().Equals(b.Symbol.ToString()) ?
|
---|
49 | (a as ConstantTreeNode).Value.CompareTo((b as ConstantTreeNode).Value) : System.String.Compare(a.Symbol.ToString(), b.Symbol.ToString());
|
---|
50 | return -1; // if b is not constant then we consider a < b because by convention Constant < Variable < Function
|
---|
51 | }
|
---|
52 | if (a is VariableTreeNode) {
|
---|
53 | if (b is ConstantTreeNode)
|
---|
54 | return 1;
|
---|
55 | if (b is VariableTreeNode)
|
---|
56 | return a.Symbol.ToString().Equals(b.Symbol.ToString()) ?
|
---|
57 | (a as VariableTreeNode).Weight.CompareTo((b as VariableTreeNode).Weight) : System.String.Compare(a.Symbol.ToString(), b.Symbol.ToString());
|
---|
58 | return -1;
|
---|
59 | }
|
---|
60 | if (b is ConstantTreeNode || b is VariableTreeNode)
|
---|
61 | return 1; // a is a Function node and is greater than Constants or Variables
|
---|
62 |
|
---|
63 | return a.Symbol.ToString().Equals(b.Symbol.ToString()) ? a.SubtreeCount.CompareTo(b.SubtreeCount) : System.String.Compare(a.Symbol.ToString(), b.Symbol.ToString());
|
---|
64 | }
|
---|
65 | }
|
---|
66 |
|
---|
67 | // tree equality
|
---|
68 | public class SymbolicExpressionTreeEqualityComparer : IEqualityComparer<ISymbolicExpressionTree> {
|
---|
69 | public bool Equals(ISymbolicExpressionTree a, ISymbolicExpressionTree b) {
|
---|
70 | return SymbolicExpressionTreeMatching.FindMatch(a, b, _mode) == 0;
|
---|
71 | }
|
---|
72 |
|
---|
73 | public int GetHashCode(ISymbolicExpressionTree tree) {
|
---|
74 | return tree.Length;
|
---|
75 | }
|
---|
76 |
|
---|
77 | private int _mode;
|
---|
78 | public void SetComparisonMode(int mode) {
|
---|
79 | _mode = mode;
|
---|
80 | }
|
---|
81 | }
|
---|
82 |
|
---|
83 | public static class SymbolicExpressionTreeMatching {
|
---|
84 | public enum SimilarityLevel {
|
---|
85 | Exact, // everything is matched bit by bit (functions and terminals)
|
---|
86 | High, // symbols are matched. leaf node types are matched
|
---|
87 | Relaxed // only symbols are matched, leafs count as wildcards
|
---|
88 | }
|
---|
89 |
|
---|
90 | public static bool IsSimilarTo(this ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, int mode) {
|
---|
91 | return FindMatch(t1, t2, mode) == 0;
|
---|
92 | }
|
---|
93 | public static bool IsSimilarTo(this ISymbolicExpressionTreeNode t1, ISymbolicExpressionTreeNode t2, int mode) {
|
---|
94 | return FindMatch(t1, t2, mode) == 0;
|
---|
95 | }
|
---|
96 |
|
---|
97 | public static bool ContainsFragment(this ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode fragment, int mode) {
|
---|
98 | var nodes = tree.IterateNodesPostfix() as List<ISymbolicExpressionTreeNode>;
|
---|
99 | var fragments = fragment.IterateNodesPostfix() as List<ISymbolicExpressionTreeNode>;
|
---|
100 | return FindMatch(nodes, fragments, mode) != -1;
|
---|
101 | }
|
---|
102 |
|
---|
103 | public static void SortSubtrees(this ISymbolicExpressionTree tree) {
|
---|
104 | SortSubtrees(tree.Root);
|
---|
105 | }
|
---|
106 |
|
---|
107 | public static void SortSubtrees(this ISymbolicExpressionTreeNode node) {
|
---|
108 | if (node.SubtreeCount > 0) {
|
---|
109 | var subtrees = node.Subtrees as List<ISymbolicExpressionTreeNode>;
|
---|
110 | if (subtrees == null) return;
|
---|
111 | subtrees.Sort(new SymbolicExpressionTreeNodeOrderingComparer());
|
---|
112 | foreach (var subtree in subtrees)
|
---|
113 | subtree.SortSubtrees();
|
---|
114 | }
|
---|
115 | }
|
---|
116 |
|
---|
117 | public static int FindMatch(ISymbolicExpressionTree a, ISymbolicExpressionTree b, int mode) {
|
---|
118 | var nodesA = a.IterateNodesPostfix() as List<ISymbolicExpressionTreeNode>;
|
---|
119 | var nodesB = b.IterateNodesPostfix() as List<ISymbolicExpressionTreeNode>;
|
---|
120 | return FindMatch(nodesA, nodesB, mode);
|
---|
121 | }
|
---|
122 | public static int FindMatch(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b, int mode) {
|
---|
123 | var nodesA = a.IterateNodesPostfix() as List<ISymbolicExpressionTreeNode>;
|
---|
124 | var nodesB = b.IterateNodesPostfix() as List<ISymbolicExpressionTreeNode>;
|
---|
125 | return FindMatch(nodesA, nodesB, mode);
|
---|
126 | }
|
---|
127 | // returns the index in the sequence 'seq', where pattern 'pat' is matched, or -1 for no match
|
---|
128 | // -1 means no match, 0 means perfect match (the sequences overlap, hence the match index is 0)
|
---|
129 | public static int FindMatch(List<ISymbolicExpressionTreeNode> seq, List<ISymbolicExpressionTreeNode> pat, int mode) {
|
---|
130 | int patlen = pat.Count;
|
---|
131 | int seqlen = seq.Count;
|
---|
132 | if (patlen == 0 || seqlen == 0) return -1;
|
---|
133 | var comparer = new SymbolicExpressionTreeNodeSimilarityComparer(mode);
|
---|
134 | if (patlen == seqlen) return seq.SequenceEqual(pat, comparer) ? 0 : -1;
|
---|
135 | for (int i = patlen; i <= seqlen; ++i) {
|
---|
136 | if (comparer.Equals(seq[i - 1], pat.Last())) // first check if last element is a match
|
---|
137 | if (seq.Skip(i - patlen).Take(patlen).SequenceEqual(pat, comparer)) // then check the whole sequence
|
---|
138 | return i - patlen;
|
---|
139 | }
|
---|
140 | return -1;
|
---|
141 | }
|
---|
142 | }
|
---|
143 | }
|
---|