Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: Add constants to grammar.

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.Cos ||
41          currentSymbol == Grammar.Inv) {
42        // Directly aggregate the single subtree
43        return new[] { AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)) };
44      }
45
46      // var, const or nonterminal symbol
47      return new[] { AggregateHashes(currentSymbol, new THashType[0]) };
48    }
49
50    private THashType[] GetAdditionSubtreeHashes(Stack<Symbol> parseStack) {
51      var uniqueChildHashes = new HashSet<THashType>();
52
53      // First subtree
54      if (parseStack.Peek() == Grammar.Addition) {
55        uniqueChildHashes.UnionWith(GetSubtreeHashes(parseStack));
56      } else {
57        var peek = parseStack.Peek();
58        uniqueChildHashes.Add(AggregateHashes(peek, GetSubtreeHashes(parseStack)));
59      }
60      // Second subtree
61      if (parseStack.Peek() == Grammar.Addition) {
62        uniqueChildHashes.UnionWith(GetSubtreeHashes(parseStack));
63      } else {
64        var peek = parseStack.Peek();
65        uniqueChildHashes.Add(AggregateHashes(peek, GetSubtreeHashes(parseStack)));
66      }
67
68      var result = uniqueChildHashes.ToArray();
69      Array.Sort(result);
70      return result;
71    }
72
73    public THashType[] GetMultiplicationSubtreeHashes(Stack<Symbol> parseStack) {
74      var childHashes = new List<THashType>();
75
76      // First subtree
77      if (parseStack.Peek() == Grammar.Multiplication) {
78        childHashes.AddRange(GetSubtreeHashes(parseStack));
79      } else {
80        childHashes.Add(AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)));
81      }
82      // Second subtree
83      if (parseStack.Peek() == Grammar.Multiplication) {
84        childHashes.AddRange(GetSubtreeHashes(parseStack));
85      } else {
86        childHashes.Add(AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)));
87      }
88
89      // Sort due to commutativity
90      childHashes.Sort();
91
92      // Cancel out inverse factors.
93      bool[] isFactorRemaining = Enumerable.Repeat(true, childHashes.Count).ToArray();
94
95      for (int i = 0; i < isFactorRemaining.Length; i++) {
96        if (!isFactorRemaining[i]) continue;
97        if (isFactorRemaining.Length <= 2) break; // Until we have constants, we can't cancel out all terms.
98
99        var currFactor = childHashes[i];
100        var invFactor = AggregateHashes(Grammar.Inv, new[] { currFactor });
101
102        int indexOfInv = childHashes.IndexOf(invFactor);
103        if (indexOfInv >= 0 && isFactorRemaining[indexOfInv]) {
104          isFactorRemaining[i] = isFactorRemaining[indexOfInv] = false;
105        }
106      }
107
108      return childHashes
109        .Where((c, i) => isFactorRemaining[i])
110        .ToArray();
111    }
112
113
114  }
115
116  public class IntHasher : Hasher<int> {
117    public IntHasher(Grammar grammar) : base(grammar) { }
118
119    protected override int AggregateHashes(Symbol operatorSym, int[] hashes) {
120      int start;
121      if ((operatorSym == Grammar.Addition || operatorSym == Grammar.Multiplication) && hashes.Length <= 1) {
122        start = 0;
123
124      } else if (operatorSym is NonterminalSymbol || operatorSym is VariableTerminalSymbol) {
125        return operatorSym.StringRepresentation.GetHashCode();
126
127      } else {
128        start = operatorSym.StringRepresentation.GetHashCode();
129      }
130
131      for (int i = 0; i < hashes.Length; i++) {
132        start = ((start << 5) + start) ^ hashes[i];
133      }
134      return start;
135    }
136  }
137
138  public class StringHasher : Hasher<string> {
139    public StringHasher(Grammar grammar) : base(grammar) { }
140
141    protected override string AggregateHashes(Symbol operatorSym, string[] hashes) {
142      var hashesArray = hashes.ToArray();
143
144      if ((operatorSym == Grammar.Addition || operatorSym == Grammar.Multiplication) && hashesArray.Length <= 1) {
145        return hashesArray[0];
146      }
147      if (operatorSym is NonterminalSymbol || operatorSym is VariableTerminalSymbol) {
148        return operatorSym.StringRepresentation;
149      }
150
151      return $"[{operatorSym.StringRepresentation} ° {string.Join(" ° ", hashesArray)}]";
152    }
153  }
154}
Note: See TracBrowser for help on using the repository browser.