Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2886_SymRegGrammarEnumeration/HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration/GrammarEnumeration/Grammar.cs @ 15950

Last change on this file since 15950 was 15930, checked in by lkammere, 7 years ago

#2886: Make grammar more configurable in grammar enumeration.

File size: 11.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Linq;
5using HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration.GrammarEnumeration;
6using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
7using HeuristicLab.Problems.DataAnalysis;
8using HeuristicLab.Problems.DataAnalysis.Symbolic;
9
10namespace HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration {
11  public enum GrammarRule {
12    MultipleTerms,
13    MultipleFactors,
14    InverseTerm,
15    Logarithm,
16    Exponentiation,
17    Sine
18  }
19
20  public class Grammar {
21
22    public Symbol StartSymbol { get; }
23
24    public Hasher<int> Hasher { get; }
25
26    #region Symbols
27
28    public IReadOnlyDictionary<Symbol, IReadOnlyList<Production>> Productions { get; }
29
30    public NonterminalSymbol Var;
31    public IReadOnlyList<VariableTerminalSymbol> VarTerminals;
32
33    public NonterminalSymbol Expr;
34    public NonterminalSymbol Term;
35    public NonterminalSymbol Factor;
36    public NonterminalSymbol LogFactor;
37    public NonterminalSymbol ExpFactor;
38    public NonterminalSymbol SinFactor;
39
40    public NonterminalSymbol SimpleExpr;
41    public NonterminalSymbol SimpleTerm;
42
43    public NonterminalSymbol InvExpr;
44    public NonterminalSymbol InvTerm;
45
46    public TerminalSymbol Addition;
47    public TerminalSymbol Multiplication;
48    public TerminalSymbol Log;
49    public TerminalSymbol Exp;
50    public TerminalSymbol Sin;
51    public TerminalSymbol Inv;
52
53    public TerminalSymbol Const;
54
55    #endregion
56
57    #region HL Symbols for Parsing ExpressionTrees
58
59    private ISymbol constSy;
60    private ISymbol varSy;
61
62    private ISymbol addSy;
63    private ISymbol mulSy;
64    private ISymbol logSy;
65    private ISymbol expSy;
66    private ISymbol divSy;
67    private ISymbol sinSy;
68
69    private ISymbol rootSy;
70    private ISymbol startSy;
71
72    private InfixExpressionFormatter infixExpressionFormatter;
73    #endregion
74
75    public Grammar(string[] variables) : this(variables, Enum.GetValues(typeof(GrammarRule)).Cast<GrammarRule>()) { }
76
77    public Grammar(string[] variables, IEnumerable<GrammarRule> includedRules) {
78      #region Define Symbols
79      Var = new NonterminalSymbol("Var");
80
81      Expr = new NonterminalSymbol("Expr");
82      Term = new NonterminalSymbol("Term");
83      Factor = new NonterminalSymbol("Factor");
84      LogFactor = new NonterminalSymbol("LogFactor");
85      ExpFactor = new NonterminalSymbol("ExpFactor");
86      SinFactor = new NonterminalSymbol("SinFactor");
87
88      SimpleExpr = new NonterminalSymbol("SimpleExpr");
89      SimpleTerm = new NonterminalSymbol("SimpleTerm");
90
91      InvExpr = new NonterminalSymbol("InvExpr");
92      InvTerm = new NonterminalSymbol("InvTerm");
93
94      Addition = new TerminalSymbol("+");
95      Multiplication = new TerminalSymbol("*");
96      Log = new TerminalSymbol("log");
97      Exp = new TerminalSymbol("exp");
98      Sin = new TerminalSymbol("sin");
99      Inv = new TerminalSymbol("inv");
100
101      Const = new TerminalSymbol("c");
102      #endregion
103
104      #region Production rules
105      StartSymbol = Expr;
106
107      Dictionary<Symbol, IReadOnlyList<Production>> productions = new Dictionary<Symbol, IReadOnlyList<Production>>();
108
109      // Map each variable to a separate production rule of the "Var" nonterminal symbol.
110      VarTerminals = variables.Select(v => new VariableTerminalSymbol(v)).ToArray();
111      productions[Var] = VarTerminals.Select(v => new Production(v)).ToArray();
112
113      // Expression Grammar Rules
114      var exprProductions = new List<Production>();
115      if (includedRules.Contains(GrammarRule.MultipleTerms))
116        exprProductions.Add(new Production(Const, Term, Multiplication, Expr, Addition));
117
118      exprProductions.Add(new Production(Const, Term, Multiplication, Const, Addition));
119      productions[Expr] = exprProductions.ToArray();
120
121      // Term Grammar Rules
122      var termProductions = new List<Production>();
123      if (includedRules.Contains(GrammarRule.MultipleFactors))
124        termProductions.Add(new Production(Factor, Term, Multiplication));
125      if (includedRules.Contains(GrammarRule.InverseTerm))
126        termProductions.Add(new Production(InvExpr, Inv));
127      termProductions.Add(new Production(Factor));
128      productions[Term] = termProductions.ToArray();
129
130      // Factor Grammar Rules
131      var factorProductions = new List<Production>();
132      factorProductions.Add(new Production(Var));
133      if (includedRules.Contains(GrammarRule.Logarithm))
134        factorProductions.Add(new Production(LogFactor));
135      if (includedRules.Contains(GrammarRule.Exponentiation))
136        factorProductions.Add(new Production(ExpFactor));
137      if (includedRules.Contains(GrammarRule.Sine))
138        factorProductions.Add(new Production(SinFactor));
139      productions[Factor] = factorProductions.ToArray();
140
141      productions[LogFactor] = new[] { new Production(SimpleExpr, Log) };
142      productions[ExpFactor] = new[] { new Production(Const, SimpleTerm, Multiplication, Exp) };
143      productions[SinFactor] = new[] { new Production(SimpleExpr, Sin) };
144
145      productions[SimpleExpr] = new[] {
146        new Production(Const, SimpleTerm, Multiplication, SimpleExpr, Addition),
147        new Production(Const, SimpleTerm, Multiplication, Const, Addition)
148      };
149
150      productions[SimpleTerm] = new[] {
151        new Production(Var, SimpleTerm, Multiplication),
152        new Production(Var)
153      };
154
155      productions[InvExpr] = new[] {
156        new Production(Const, InvTerm, Multiplication, InvExpr, Addition),
157        new Production(Const, InvTerm, Multiplication, Const, Addition)
158      };
159
160      productions[InvTerm] = new[] {
161        new Production(Factor, InvTerm, Multiplication),
162        new Production(Factor)
163      };
164
165      Productions = productions;
166      #endregion
167
168      #region Parsing to SymbolicExpressionTree
169      var symbolicExpressionGrammar = new TypeCoherentExpressionGrammar();
170      symbolicExpressionGrammar.ConfigureAsDefaultRegressionGrammar();
171
172      constSy = symbolicExpressionGrammar.Symbols.OfType<Constant>().First();
173      varSy = symbolicExpressionGrammar.Symbols.OfType<Variable>().First();
174      addSy = symbolicExpressionGrammar.Symbols.OfType<Addition>().First();
175      mulSy = symbolicExpressionGrammar.Symbols.OfType<Multiplication>().First();
176      logSy = symbolicExpressionGrammar.Symbols.OfType<Logarithm>().First();
177      expSy = symbolicExpressionGrammar.Symbols.OfType<Exponential>().First();
178      divSy = symbolicExpressionGrammar.Symbols.OfType<Division>().First();
179      sinSy = symbolicExpressionGrammar.Symbols.OfType<Sine>().First();
180
181      rootSy = symbolicExpressionGrammar.Symbols.OfType<ProgramRootSymbol>().First();
182      startSy = symbolicExpressionGrammar.Symbols.OfType<StartSymbol>().First();
183
184      infixExpressionFormatter = new InfixExpressionFormatter();
185      #endregion
186
187      Hasher = new IntHasher(this);
188    }
189
190    public int GetComplexity(SymbolString s) {
191      int c = 0;
192      int length = s.Count();
193      for (int i = 0; i < length; i++) {
194        if (s[i] is NonterminalSymbol || s[i] is VariableTerminalSymbol) c++;
195      }
196      return c;
197    }
198
199    public double EvaluatePhrase(SymbolString s, IRegressionProblemData problemData, bool optimizeConstants) {
200      SymbolicExpressionTree tree = ParseSymbolicExpressionTree(s);
201
202      double r2 = RSquaredEvaluator.Evaluate(problemData, tree, optimizeConstants);
203
204      return r2;
205    }
206
207    #region Parse to SymbolicExpressionTree
208
209    public string ToInfixString(SymbolString sentence) {
210      Debug.Assert(sentence.Any(), "Trying to evaluate empty sentence!");
211      Debug.Assert(sentence.All(s => s is TerminalSymbol), "Trying to evaluate symbol sequence with nonterminalsymbols!");
212
213      return infixExpressionFormatter.Format(ParseSymbolicExpressionTree(sentence));
214    }
215
216    public SymbolicExpressionTree ParseSymbolicExpressionTree(SymbolString sentence) {
217      Debug.Assert(sentence.Any(), "Trying to evaluate empty sentence!");
218
219      var rootNode = rootSy.CreateTreeNode();
220      var startNode = startSy.CreateTreeNode();
221      rootNode.AddSubtree(startNode);
222
223      Stack<Symbol> parseStack = new Stack<Symbol>(sentence);
224      startNode.AddSubtree(ParseSymbolicExpressionTree(parseStack));
225
226      return new SymbolicExpressionTree(rootNode);
227    }
228
229    public ISymbolicExpressionTreeNode ParseSymbolicExpressionTree(Stack<Symbol> parseStack) {
230      Symbol currentSymbol = parseStack.Pop();
231
232      ISymbolicExpressionTreeNode parsedSubTree = null;
233
234      if (currentSymbol == Addition) {
235        parsedSubTree = addSy.CreateTreeNode();
236        ISymbolicExpressionTreeNode rightSubtree = ParseSymbolicExpressionTree(parseStack);
237        if (rightSubtree is ConstantTreeNode) {
238          ((ConstantTreeNode)rightSubtree).Value = 0.0;
239        }
240        parsedSubTree.AddSubtree(rightSubtree); // left part
241
242        ISymbolicExpressionTreeNode leftSubtree = ParseSymbolicExpressionTree(parseStack);
243        if (leftSubtree is ConstantTreeNode) {
244          ((ConstantTreeNode)leftSubtree).Value = 0.0;
245        }
246        parsedSubTree.AddSubtree(leftSubtree); // right part
247
248      } else if (currentSymbol == Multiplication) {
249        parsedSubTree = mulSy.CreateTreeNode();
250        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack)); // left part
251        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack)); // right part
252
253      } else if (currentSymbol == Log) {
254        parsedSubTree = logSy.CreateTreeNode();
255        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
256
257      } else if (currentSymbol == Exp) {
258        parsedSubTree = expSy.CreateTreeNode();
259        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
260
261      } else if (currentSymbol == Sin) {
262        parsedSubTree = sinSy.CreateTreeNode();
263        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
264
265      } else if (currentSymbol == Inv) {
266        parsedSubTree = divSy.CreateTreeNode();
267        ConstantTreeNode dividend = (ConstantTreeNode)constSy.CreateTreeNode();
268        dividend.Value = 1.0;
269        parsedSubTree.AddSubtree(dividend);
270        parsedSubTree.AddSubtree(ParseSymbolicExpressionTree(parseStack));
271
272      } else if (currentSymbol == Const) {
273        ConstantTreeNode constNode = (ConstantTreeNode)constSy.CreateTreeNode();
274        constNode.Value = 1.0;
275        parsedSubTree = constNode;
276
277      } else if (currentSymbol is VariableTerminalSymbol) {
278        VariableTreeNode varNode = (VariableTreeNode)varSy.CreateTreeNode();
279        varNode.Weight = 1.0;
280        varNode.VariableName = currentSymbol.StringRepresentation;
281        parsedSubTree = varNode;
282
283      } else if (currentSymbol is NonterminalSymbol) {
284        ConstantTreeNode constNode = (ConstantTreeNode)constSy.CreateTreeNode();
285        constNode.Value = 0.0;
286        parsedSubTree = constNode;
287      }
288
289      Debug.Assert(parsedSubTree != null);
290      return parsedSubTree;
291    }
292    #endregion
293  }
294}
Note: See TracBrowser for help on using the repository browser.