Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/08/18 10:54:04 (6 years ago)
Author:
lkammere
Message:

#2886: Fix Equals methods in Symbols.
Move semantical hashing of phrases to separate class.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2886_SymRegGrammarEnumeration/HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration/GrammarEnumeration/Grammar.cs

    r15828 r15832  
    1 using System;
    2 using System.Collections.Generic;
     1using System.Collections.Generic;
    32using System.Diagnostics;
    43using System.Linq;
    54using HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration.GrammarEnumeration;
    6 using HeuristicLab.Common;
    75using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    86using HeuristicLab.Problems.DataAnalysis.Symbolic;
     
    1210
    1311    public Symbol StartSymbol { get; }
     12
     13    public Hasher<int> Hasher { get; }
    1414
    1515    #region Symbols
     
    146146      infixExpressionFormatter = new InfixExpressionFormatter();
    147147      #endregion
    148     }
    149 
    150     #region Hashing
    151     public int CalcHashCode(SymbolString sentence) {
    152       return CalcHashCode<int>(sentence, AggregateIntHashes);
    153     }
    154 
    155     private int CalcHashCode<THashType>(SymbolString sentence, Func<Symbol, THashType[], THashType> aggregateFunction) {
    156       Debug.Assert(sentence.Any(), "Trying to evaluate empty sentence!");
    157 
    158       Stack<Symbol> parseStack = new Stack<Symbol>(sentence);
    159 
    160       Symbol peek = parseStack.Peek();
    161       return aggregateFunction(peek, GetSubtreeHashes(parseStack, aggregateFunction)).GetHashCode();
    162     }
    163 
    164     private THashType[] GetSubtreeHashes<THashType>(Stack<Symbol> parseStack, Func<Symbol, THashType[], THashType> aggregateHashes) {
    165       Symbol currentSymbol = parseStack.Pop();
    166 
    167       // ADDITION
    168       if (currentSymbol == Addition) {
    169         var uniqueChildHashes = new HashSet<THashType>();
    170 
    171         // First subtree
    172         if (parseStack.Peek() == Addition) {
    173           uniqueChildHashes.UnionWith(GetSubtreeHashes(parseStack, aggregateHashes));
    174         } else {
    175           var peek = parseStack.Peek();
    176           uniqueChildHashes.Add(aggregateHashes(peek, GetSubtreeHashes(parseStack, aggregateHashes)));
    177         }
    178         // Second subtree
    179         if (parseStack.Peek() == Addition) {
    180           uniqueChildHashes.UnionWith(GetSubtreeHashes(parseStack, aggregateHashes));
    181         } else {
    182           var peek = parseStack.Peek();
    183           uniqueChildHashes.Add(aggregateHashes(peek, GetSubtreeHashes(parseStack, aggregateHashes)));
    184         }
    185 
    186         var result = uniqueChildHashes.ToArray();
    187         Array.Sort(result);
    188         return result;
    189       }
    190 
    191       // MULTIPLICATION
    192       if (currentSymbol == Multiplication) {
    193         var childHashes = new List<THashType>();
    194 
    195         // First subtree
    196         if (parseStack.Peek() == Multiplication) {
    197           childHashes.AddRange(GetSubtreeHashes(parseStack, aggregateHashes));
    198         } else {
    199           childHashes.Add(aggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack, aggregateHashes)));
    200         }
    201         // Second subtree
    202         if (parseStack.Peek() == Multiplication) {
    203           childHashes.AddRange(GetSubtreeHashes(parseStack, aggregateHashes));
    204         } else {
    205           childHashes.Add(aggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack, aggregateHashes)));
    206         }
    207 
    208         // Sort due to commutativity
    209         childHashes.Sort();
    210 
    211         // Cancel out inverse factors.
    212         bool[] isFactorRemaining = Enumerable.Repeat(true, childHashes.Count).ToArray();
    213 
    214         for (int i = 0; i < isFactorRemaining.Length; i++) {
    215           if (!isFactorRemaining[i]) continue;
    216           if (isFactorRemaining.Length <= 2) break; // Until we have constants, we can't cancel out all terms.
    217 
    218           var currFactor = childHashes[i];
    219           var invFactor = aggregateHashes(Inv, new[] { currFactor });
    220 
    221           int indexOfInv = childHashes.IndexOf(invFactor);
    222           if (indexOfInv >= 0 && isFactorRemaining[indexOfInv]) {
    223             isFactorRemaining[i] = isFactorRemaining[indexOfInv] = false;
    224           }
    225         }
    226 
    227         return childHashes
    228           .Where((c, i) => isFactorRemaining[i])
    229           .ToArray();
    230       }
    231 
    232       // LOG, EXP, SIN, INV
    233       if (currentSymbol == Log || currentSymbol == Exp ||
    234           currentSymbol == Sin || currentSymbol == Cos ||
    235           currentSymbol == Inv) {
    236         return new[] { aggregateHashes(parseStack.Peek(), GetSubtreeHashes(parseStack, aggregateHashes)) };
    237       }
    238 
    239       // var or nonterminal symbol
    240       return new[] { aggregateHashes(currentSymbol, new THashType[0]) };
    241     }
    242 
    243     private string AggregateStringHashes(Symbol operatorSym, string[] hashes) {
    244       var hashesArray = hashes.ToArray();
    245 
    246       if ((operatorSym == Addition || operatorSym == Multiplication) && hashesArray.Length <= 1) {
    247         return hashesArray[0];
    248       }
    249       if (operatorSym is NonterminalSymbol || ((TerminalSymbol)operatorSym).IsVariable) {
    250         return operatorSym.StringRepresentation;
    251       }
    252 
    253       return $"[{operatorSym.StringRepresentation} ° {string.Join(" ° ", hashesArray)}]";
    254     }
    255 
    256     private int AggregateIntHashes(Symbol operatorSym, int[] hashes) {
    257       int start;
    258       if ((operatorSym == Addition || operatorSym == Multiplication) && hashes.Length <= 1) {
    259         start = 0;
    260 
    261       } else if (operatorSym is NonterminalSymbol || ((TerminalSymbol)operatorSym).IsVariable) {
    262         return operatorSym.StringRepresentation.GetHashCode();
    263 
    264       } else {
    265         start = operatorSym.StringRepresentation.GetHashCode();
    266       }
    267 
    268       for (int i = 0; i < hashes.Length; i++) {
    269         start = ((start << 5) + start) ^ hashes[i];
    270       }
    271       return start;
    272     }
    273     #endregion
     148
     149      Hasher = new IntHasher(this);
     150    }
    274151
    275152    #region Parse to SymbolicExpressionTree
     
    323200        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
    324201
    325       } else if (currentSymbol ==  Cos) {
     202      } else if (currentSymbol == Cos) {
    326203        parsedSubTree = cosSy.CreateTreeNode();
    327204        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
     
    334211        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
    335212
    336       } else if (currentSymbol.IsVariable) {
     213      } else if (currentSymbol is VariableTerminalSymbol) {
    337214        VariableTreeNode varNode = (VariableTreeNode)varSy.CreateTreeNode();
    338215        varNode.Weight = 1.0;
Note: See TracChangeset for help on using the changeset viewer.