Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2886_SymRegGrammarEnumeration/HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration/Hashing/Hasher.cs @ 15851

Last change on this file since 15851 was 15851, checked in by lkammere, 6 years ago

#2886: Remove cosine terminal symbols.

File size: 5.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Linq;
5
6namespace HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration.GrammarEnumeration {
7  public abstract class Hasher<THashType> {
8    protected Hasher(Grammar grammar) {
9      Grammar = grammar;
10    }
11
12    protected Grammar Grammar { get; }
13
14    protected abstract THashType AggregateHashes(Symbol operatorSym, THashType[] hashes);
15
16    public int CalcHashCode(SymbolString sentence) {
17      Debug.Assert(sentence.Any(), "Trying to evaluate empty sentence!");
18
19      Stack<Symbol> parseStack = new Stack<Symbol>(sentence);
20
21      Symbol peek = parseStack.Peek();
22      return AggregateHashes(peek, GetSubtreeHashes(parseStack)).GetHashCode();
23    }
24
25    private THashType[] GetSubtreeHashes(Stack<Symbol> parseStack) {
26      Symbol currentSymbol = parseStack.Pop();
27
28      // ADDITION
29      if (currentSymbol == Grammar.Addition) {
30        return GetAdditionSubtreeHashes(parseStack);
31      }
32
33      // MULTIPLICATION
34      if (currentSymbol == Grammar.Multiplication) {
35        return GetMultiplicationSubtreeHashes(parseStack);
36      }
37
38      // LOG, EXP, SIN, INV
39      if (currentSymbol == Grammar.Log || currentSymbol == Grammar.Exp ||
40          currentSymbol == Grammar.Sin || currentSymbol == Grammar.Inv) {
41        // Directly aggregate the single subtree
42        return new[] { AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)) };
43      }
44
45      // var, const or nonterminal symbol
46      return new[] { AggregateHashes(currentSymbol, new THashType[0]) };
47    }
48
49    private THashType[] GetAdditionSubtreeHashes(Stack<Symbol> parseStack) {
50      var uniqueChildHashes = new HashSet<THashType>();
51
52      // First subtree
53      if (parseStack.Peek() == Grammar.Addition) {
54        uniqueChildHashes.UnionWith(GetSubtreeHashes(parseStack));
55      } else {
56        var peek = parseStack.Peek();
57        uniqueChildHashes.Add(AggregateHashes(peek, GetSubtreeHashes(parseStack)));
58      }
59      // Second subtree
60      if (parseStack.Peek() == Grammar.Addition) {
61        uniqueChildHashes.UnionWith(GetSubtreeHashes(parseStack));
62      } else {
63        var peek = parseStack.Peek();
64        uniqueChildHashes.Add(AggregateHashes(peek, GetSubtreeHashes(parseStack)));
65      }
66
67      var result = uniqueChildHashes.ToArray();
68      Array.Sort(result);
69      return result;
70    }
71
72    public THashType[] GetMultiplicationSubtreeHashes(Stack<Symbol> parseStack) {
73      var childHashes = new List<THashType>();
74
75      // First subtree
76      if (parseStack.Peek() == Grammar.Multiplication) {
77        childHashes.AddRange(GetSubtreeHashes(parseStack));
78      } else {
79        childHashes.Add(AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)));
80      }
81      // Second subtree
82      if (parseStack.Peek() == Grammar.Multiplication) {
83        childHashes.AddRange(GetSubtreeHashes(parseStack));
84      } else {
85        childHashes.Add(AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)));
86      }
87
88      // Sort due to commutativity
89      childHashes.Sort();
90
91      // Cancel out inverse factors.
92      bool[] isFactorRemaining = Enumerable.Repeat(true, childHashes.Count).ToArray();
93
94      for (int i = 0; i < isFactorRemaining.Length; i++) {
95        if (!isFactorRemaining[i]) continue;
96        if (isFactorRemaining.Length <= 2) break; // Until we have constants, we can't cancel out all terms.
97
98        var currFactor = childHashes[i];
99        var invFactor = AggregateHashes(Grammar.Inv, new[] { currFactor });
100
101        int indexOfInv = childHashes.IndexOf(invFactor);
102        if (indexOfInv >= 0 && isFactorRemaining[indexOfInv]) {
103          isFactorRemaining[i] = isFactorRemaining[indexOfInv] = false;
104        }
105      }
106
107      return childHashes
108        .Where((c, i) => isFactorRemaining[i])
109        .ToArray();
110    }
111
112
113  }
114
115  public class IntHasher : Hasher<int> {
116    public IntHasher(Grammar grammar) : base(grammar) { }
117
118    protected override int AggregateHashes(Symbol operatorSym, int[] hashes) {
119      int start;
120      if ((operatorSym == Grammar.Addition || operatorSym == Grammar.Multiplication) && hashes.Length <= 1) {
121        start = 0;
122
123      } else if (operatorSym is NonterminalSymbol || operatorSym is VariableTerminalSymbol) {
124        return operatorSym.StringRepresentation.GetHashCode();
125
126      } else {
127        start = operatorSym.StringRepresentation.GetHashCode();
128      }
129
130      for (int i = 0; i < hashes.Length; i++) {
131        start = ((start << 5) + start) ^ hashes[i];
132      }
133      return start;
134    }
135  }
136
137  public class StringHasher : Hasher<string> {
138    public StringHasher(Grammar grammar) : base(grammar) { }
139
140    protected override string AggregateHashes(Symbol operatorSym, string[] hashes) {
141      var hashesArray = hashes.ToArray();
142
143      if ((operatorSym == Grammar.Addition || operatorSym == Grammar.Multiplication) && hashesArray.Length <= 1) {
144        return hashesArray[0];
145      }
146      if (operatorSym is NonterminalSymbol || operatorSym is VariableTerminalSymbol) {
147        return operatorSym.StringRepresentation;
148      }
149
150      return $"[{operatorSym.StringRepresentation} ° {string.Join(" ° ", hashesArray)}]";
151    }
152  }
153}
Note: See TracBrowser for help on using the repository browser.