Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: Refactor RSquaredEvaluator as a standalone ParameterizedNamedItem which is a parameter of the algorithm. Implement BestSolutionAnalyzer analyzer for quality statistics. Add license headers where missing.

File size: 7.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 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.Diagnostics;
25using System.Linq;
26using HeuristicLab.Common;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration {
30  [StorableClass]
31  public abstract class Hasher<THashType> : DeepCloneable {
32    protected Hasher(Grammar grammar) {
33      Grammar = grammar;
34    }
35
36    protected Hasher(Hasher<THashType> original, Cloner cloner) : base(original, cloner) {
37      Grammar = cloner.Clone(original.Grammar);
38    }
39
40    [Storable]
41    protected Grammar Grammar { get; private set; }
42
43    protected abstract THashType AggregateHashes(Symbol operatorSym, IList<THashType> hashes);
44
45    public int CalcHashCode(SymbolList sentence) {
46      Debug.Assert(sentence.Any(), "Trying to evaluate empty sentence!");
47
48      Stack<Symbol> parseStack = new Stack<Symbol>(sentence);
49
50      Symbol peek = parseStack.Peek();
51      return AggregateHashes(peek, GetSubtreeHashes(parseStack)).GetHashCode();
52    }
53
54    [StorableConstructor]
55    protected Hasher(bool deserializing) { }
56
57    private IList<THashType> GetSubtreeHashes(Stack<Symbol> parseStack) {
58      Symbol currentSymbol = parseStack.Pop();
59
60      // ADDITION
61      if (currentSymbol == Grammar.Addition) {
62        return GetAdditionSubtreeHashes(parseStack);
63      }
64
65      // MULTIPLICATION
66      if (currentSymbol == Grammar.Multiplication) {
67        return GetMultiplicationSubtreeHashes(parseStack);
68      }
69
70      // LOG, EXP, SIN, INV
71      if (currentSymbol == Grammar.Log || currentSymbol == Grammar.Exp ||
72          currentSymbol == Grammar.Sin || currentSymbol == Grammar.Inv) {
73        // Directly aggregate the single subtree
74        return new[] { AggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack)) };
75      }
76
77      // var, const or nonterminal symbol
78      return new[] { AggregateHashes(currentSymbol, new THashType[0]) };
79    }
80
81    private void AddAdditionChildHashes(HashSet<THashType> hashSet, Stack<Symbol> symbolStack) {
82      var peek = symbolStack.Peek();
83      var hashes = GetSubtreeHashes(symbolStack); // will pop the stack
84
85      if (peek == Grammar.Addition)
86        hashSet.UnionWith(hashes);
87      else
88        hashSet.Add(AggregateHashes(peek, hashes));
89    }
90
91    private IList<THashType> GetAdditionSubtreeHashes(Stack<Symbol> parseStack) {
92      var uniqueChildHashes = new HashSet<THashType>();
93
94      AddAdditionChildHashes(uniqueChildHashes, parseStack); // first child
95      AddAdditionChildHashes(uniqueChildHashes, parseStack); // second child
96
97      var result = uniqueChildHashes.ToArray();
98      Array.Sort(result);
99      return result;
100    }
101
102    private void AddMultiplicationChildHashes(List<THashType> hashList, Stack<Symbol> symbolStack) {
103      var peek = symbolStack.Peek();
104      var hashes = GetSubtreeHashes(symbolStack);
105      if (peek == Grammar.Multiplication)
106        hashList.AddRange(hashes);
107      else
108        hashList.Add(AggregateHashes(peek, hashes));
109    }
110
111    public IList<THashType> GetMultiplicationSubtreeHashes(Stack<Symbol> parseStack) {
112      var childHashes = new List<THashType>();
113
114      AddMultiplicationChildHashes(childHashes, parseStack); // first child
115      AddMultiplicationChildHashes(childHashes, parseStack); // second child
116
117      // Sort due to commutativity
118      childHashes.Sort();
119
120      if (childHashes.Count <= 2)
121        return childHashes;
122
123      // Cancel out inverse factors.
124      var isInvFactor = new bool[childHashes.Count];
125      bool foundInvFactor = false;
126      for (int i = 0; i < isInvFactor.Length; i++) {
127        if (isInvFactor[i]) continue;
128
129        var currFactor = childHashes[i];
130        var invFactor = AggregateHashes(Grammar.Inv, new[] { currFactor });
131
132        int indexOfInv = childHashes.IndexOf(invFactor);
133        if (indexOfInv >= 0 && !isInvFactor[indexOfInv]) {
134          isInvFactor[i] = isInvFactor[indexOfInv] = true;
135          foundInvFactor = true;
136        }
137      }
138
139      if (!foundInvFactor)
140        return childHashes;
141
142      return childHashes
143        .Where((c, i) => !isInvFactor[i])
144        .ToArray();
145    }
146  }
147
148  [StorableClass]
149  public class IntHasher : Hasher<int> {
150    public IntHasher(Grammar grammar) : base(grammar) { }
151
152    public IntHasher(IntHasher original, Cloner cloner) : base(original, cloner) { }
153
154    public override IDeepCloneable Clone(Cloner cloner) {
155      return new IntHasher(this, cloner);
156    }
157
158    [StorableConstructor]
159    protected IntHasher(bool deserializing) : base(deserializing) { }
160
161    protected override int AggregateHashes(Symbol operatorSym, IList<int> hashes) {
162      int start;
163      if ((operatorSym == Grammar.Addition || operatorSym == Grammar.Multiplication) && hashes.Count <= 1) {
164        start = 0;
165
166      } else if (operatorSym is NonterminalSymbol || operatorSym is VariableTerminalSymbol) {
167        return operatorSym.StringRepresentation.GetHashCode();
168
169      } else {
170        start = operatorSym.StringRepresentation.GetHashCode();
171      }
172
173      for (int i = 0; i < hashes.Count; i++) {
174        start = ((start << 5) + start) ^ hashes[i];
175      }
176      return start;
177    }
178  }
179
180  [StorableClass]
181  public class StringHasher : Hasher<string> {
182    public StringHasher(Grammar grammar) : base(grammar) { }
183
184    public StringHasher(StringHasher original, Cloner cloner) : base(original, cloner) { }
185
186    public override IDeepCloneable Clone(Cloner cloner) {
187      return new StringHasher(this, cloner);
188    }
189
190    [StorableConstructor]
191    protected StringHasher(bool deserializing) : base(deserializing) { }
192
193    protected override string AggregateHashes(Symbol operatorSym, IList<string> hashes) {
194      var hashesArray = hashes.ToArray();
195
196      if ((operatorSym == Grammar.Addition || operatorSym == Grammar.Multiplication) && hashesArray.Length <= 1) {
197        return hashesArray[0];
198      }
199      if (operatorSym is NonterminalSymbol || operatorSym is VariableTerminalSymbol) {
200        return operatorSym.StringRepresentation;
201      }
202
203      return $"[{operatorSym.StringRepresentation} ° {string.Join(" ° ", hashesArray)}]";
204    }
205  }
206}
Note: See TracBrowser for help on using the repository browser.