Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/HeuristicLab.Problems.GrammaticalOptimization.SymbReg/ExpressionCompiler.cs @ 11972

Last change on this file since 11972 was 11972, checked in by gkronber, 9 years ago

#2283 new experiments

File size: 5.5 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics.Eventing.Reader;
4using System.Linq;
5using System.Runtime.CompilerServices;
6using System.Runtime.Remoting.Messaging;
7using System.Text;
8using System.Threading.Tasks;
9using AutoDiff;
10using HeuristicLab.Common;
11
12namespace HeuristicLab.Problems.GrammaticalOptimization {
13  public class ExpressionCompiler {
14    private string sentence;
15    private int syIdx;
16    // compiles sentences from L(G(Expr)) using AutoDiff
17    // does not compile to IL it is only necessary to calculate gradients for parameter optimization
18    // Expr -> Term { ('+' | '-' | '^' ) Term }
19    // Term -> Fact { ('*' | '%') Fact }
20    // Fact -> '!' Expr | '(' Expr ')' | Var | const
21    // Var -> 'a'..'z'
22    // const -> '0' .. '9'
23
24    // constants are completely ignored, instead we introduce a multiplicative constant factor for each term and an additive constant term for each expression
25
26    // for boolean problems the symbol * representes the AND operator, the symbol + represents the OR operator, ! = NOT, ^ = XOR
27
28    public void Compile(string sentence, out Term f, Variable[] variables, out Variable[] constants) {
29      InitLex(sentence);
30      var constantsList = new List<Variable>();
31      f = Expr(variables, constantsList);
32      constants = constantsList.ToArray();
33    }
34
35    private void InitLex(string sentence) {
36      this.sentence = sentence;
37      this.syIdx = 0;
38    }
39
40    private char CurSy() {
41      if (syIdx >= sentence.Length) return '\0';
42      return sentence[syIdx];
43    }
44    private void NewSy() {
45      if (syIdx < sentence.Length) syIdx++;
46    }
47
48    // helper for xor
49    private Term Not(Term x) {
50      return 1.0 - x;
51    }
52
53    private Term Expr(IList<Variable> variables, IList<Variable> constants) {
54      var terms = new List<Term>();
55      terms.Add(Term(variables, constants));
56      var curSy = CurSy();
57      while (curSy == '+' || curSy == '-' || curSy == '^') {
58        if (curSy == '+') {
59          NewSy();
60          terms.Add(Term(variables, constants));
61        } else if (curSy == '-') {
62          NewSy();
63          terms.Add(-Term(variables, constants)); // minus
64        } else {
65          NewSy();
66          throw new NotImplementedException();
67          // var e = Expr(variables, constants);
68          // r = Not(r) * e + r * Not(e); // xor = (!x AND y) OR (x AND !y)
69        }
70        curSy = CurSy();
71      }
72
73      // at this point we might have multiple constants in the list of terms but we only need one of them
74      var firstConstant = terms.OfType<Variable>().FirstOrDefault(); // if a term is only a variable then it must be a constant (otherwise (for real variables) it would be a product of two constants)
75      if (firstConstant == null) {
76        // no constant found => add a constant offset for each full expression
77        var offset = new Variable();
78        constants.Add(offset);
79        terms.Add(offset);
80      } else {
81        // there is already a constant => remove all others if there are more
82        var otherConsts = terms.OfType<Variable>().Where(t => t != firstConstant).ToArray();
83        foreach (var otherConst in otherConsts) {
84          terms.Remove(otherConst);
85          constants.Remove(otherConst);
86        }
87      }
88      return TermBuilder.Sum(terms);
89    }
90
91    private Term Term(IList<Variable> variables, IList<Variable> constants) {
92      var factors = new List<Term>();
93      var f = Fact(variables, constants);
94      if (f != null) factors.Add(f);
95      var curSy = CurSy();
96      while (curSy == '*' || curSy == '%') {
97        if (curSy == '*') {
98          NewSy();
99          f = Fact(variables, constants); // fact might return null (for constants)
100          if (f != null) factors.Add(f);
101        } else {
102          NewSy();
103          f = Fact(variables, constants);
104          if (f != null) factors.Add(1.0 / f); // cannot use protected division here
105        }
106        curSy = CurSy();
107      }
108
109      // generate a constant factor (scale) for each full term
110      // since we ignore constants in the string it could be possible that factors is still empty at this point
111      var scale = new Variable();
112      constants.Add(scale);
113      factors.Add(scale);
114
115      if (factors.Count == 1) return factors[0];
116      else if (factors.Count == 2) return factors[0] * factors[1];
117      else return TermBuilder.Product(factors[0], factors[1], factors.Skip(2).ToArray());
118    }
119
120    private Term Fact(IList<Variable> variables, IList<Variable> constants) {
121      Term r = null;
122      var curSy = CurSy();
123      if (curSy == '!') {
124        NewSy();
125        r = Not(Expr(variables, constants));
126      } else if (curSy == '(') {
127        NewSy();
128        r = Expr(variables, constants);
129        if (CurSy() != ')') throw new ArgumentException();
130        NewSy();
131      } else if (curSy >= 'a' && curSy <= 'z') {
132        var varIdx = (byte)curSy - (byte)'a';
133        if (varIdx >= variables.Count) throw new ArgumentException();
134        r = variables[varIdx];
135        NewSy();
136      } else if (curSy >= '0' && curSy <= '9') {
137        int o = (byte)curSy - (byte)'0';
138        //int o = Convert.ToByte(CurSy()) - Convert.ToByte('a');
139        if (o < 0 || o >= 10) throw new ArgumentException();
140
141        // completely ignore existing constants
142
143        // var newConst = new Variable();
144        // constants.Add(newConst);
145        // r = newConst;
146        NewSy();
147      } else throw new ArgumentException();
148      return r;
149    }
150
151  }
152}
Note: See TracBrowser for help on using the repository browser.