Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GPDL/CodeGenerator/BruteForceCodeGen.cs @ 10062

Last change on this file since 10062 was 10062, checked in by gkronber, 11 years ago

#2026 worked on brute force code generator, removed unused references, worked on compatibility with mono.

File size: 12.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Threading.Tasks;
7
8namespace CodeGenerator {
9  public class BruteForceCodeGen {
10
11    private string usings = @"
12using System.Collections.Generic;
13using System.Linq;
14using System;
15";
16
17    private string solverTemplate = @"
18namespace ?PROBLEMNAME? {
19  private static class Grammar {
20    ?GRAMMARCLASSCODE?
21  }
22  private sealed class PartiallyProcessedSeq {
23    private PartiallyProcessedSeq parent;
24    private int alt;
25    private IEnumerable<string> remaining;
26    public PartiallyProcessedSeq(IEnumerable<string> alternative) {
27      this.remaining = alternative;
28    }
29    public PartiallyProcessedSeq CreateAlternative(int p, IEnumerable<string> alternative) {
30      var child = new PartiallyProcessedSeq(alternative.Concat(remaining));
31      child.parent = this;
32    }
33    public bool TryProcessToNextSymbolWithAlternatives(out string symbol) {
34      remaining = remaining.SkipWhile(s=>Grammar.NumberOfAlternatives(s)==0);
35      if(remaining.Any()) {
36        symbol = remaining.First();
37        remaining = remaining.Skip(1);
38        return true;
39      } else {
40        symbol = null;
41        return false;
42      }
43     
44    }
45    public IEnumerable<int> Path {
46      get {
47        var cur = this;
48        var List<int> path = new List<int>();
49        while(cur.parent!=null) {
50          path.Append(cur.p);
51          cur = cur.parent;
52        }
53        return path.Reverse();
54      }
55    }
56  }
57  public sealed class ?IDENT?Solver {
58
59    public static void Main(string[] args) {
60      var solver = new ?IDENT?Solver();
61      solver.Start();
62    }
63
64    public ?IDENT?Solver() {
65      Initialize();
66    }   
67
68    private void Initialize() {
69      ?INITCODE?
70    }
71
72    private bool IsBetter(double a, double b) {
73      ?MAXIMIZATION? ? a > b : a < b;
74    }
75
76    private IEnumerable<IEnumerator<int>> GeneratePaths() {
77      var queue = new Queue<PartiallyProcessedSeq>();
78      foreach(var alt in Grammar.GetAlternatives(Grammar.RootSymbol))
79        queue.Enqueue(new PartiallyProcessedSeq(alt));
80
81      while(queue.Count > 0) {
82        var e = queue.Dequeue();
83        string ntSöymbol;
84        if(e.TryProcessToNextNtSymbol(out ntSymbol)) {
85          int i=0;
86          foreach(var alt in Grammar.GetAlternatives(symbol)) {
87            queue.Enqueue(new e.CreateAlternative(i++, alt));
88          }
89        } else {
90          yield return e.Path;
91        }
92      }
93    }
94
95    ?PATHGENERATORCODE?
96
97    private void Start() {
98      // generate possible paths through the grammar and evaluate each of them   
99      var bestF = ?MAXIMIZATION? ? double.NegativeInfinity : double.PositiveInfinity;
100      foreach(var path in GeneratePaths()) {
101        currentPath = path;
102        var f = Calculate();
103        if(IsBetter(f, bestF)) bestF = f;
104        Console.WriteLine(""{0}\t{1}"",bestF, f);
105      }
106    }
107
108    private IEnumerator<int> currentPath;
109
110    public double Calculate() {
111      try {
112        ?FITNESSFUNCTION?
113      } catch(Exception e) {
114        throw;
115      }
116    }
117
118    ?ADDITIONALCODE?
119
120    ?INTERPRETERSOURCE?
121
122    ?CONSTRAINTSSOURCE?
123  }
124}";
125
126
127    /// <summary>
128    /// Generates the source code for a brute force searcher that can be compiled with a C# compiler
129    /// </summary>
130    /// <param name="ast">An abstract syntax tree for a GPDL file</param>
131    public void Generate(GPDefNode ast) {
132      var problemSourceCode = new StringBuilder();
133      problemSourceCode.AppendLine(usings);
134
135      GenerateProblem(ast, problemSourceCode);
136
137      problemSourceCode.Replace("?PROBLEMNAME?", ast.Name);
138
139      // write to a file for debugging
140      using (var stream = new StreamWriter(ast.Name + ".cs")) {
141        stream.WriteLine(problemSourceCode.ToString());
142      }
143    }
144
145    private void GenerateProblem(GPDefNode ast, StringBuilder problemSourceCode) {
146      var problemClassCode =
147        solverTemplate
148          .Replace("?MAXIMIZATION?", ast.FitnessFunctionNode.Maximization.ToString())
149          .Replace("?GRAMMARCLASSCODE?", GenerateGrammarClassCode(ast))
150          .Replace("?IDENT?", ast.Name)
151          .Replace("?FITNESSFUNCTION?", ast.FitnessFunctionNode.SrcCode)
152          .Replace("?INTERPRETERSOURCE?", GenerateInterpreterSource(ast))
153          .Replace("?INITCODE?", ast.InitCodeNode.SrcCode)
154          .Replace("?ADDITIONALCODE?", ast.ClassCodeNode.SrcCode)
155          .Replace("?CONSTRAINTSSOURCE?", GenerateConstraintMethods(ast.Terminals))
156          .Replace("?PATHGENERATORCODE?", GeneratePathGeneratorCode(ast))
157          ;
158
159      problemSourceCode.AppendLine(problemClassCode).AppendLine();
160    }
161
162    private string GenerateGrammarClassCode(GPDefNode ast) {
163      var sb = new StringBuilder();
164      // RootSymbol
165      sb.AppendFormat("public static string RootSymbol {{ get {{ return {0}; }} }}", ast.Rules.First().NtSymbol).AppendLine();
166      // GetAlternatives
167      sb.AppendFormat("public static IEnumerable<IEnumerable<string>> GetAlternatives(string symbol) {{");
168      sb.AppendFormat("switch(symbol) {{ ").AppendLine();
169      foreach (var ntSymbol in ast.NonTerminals) {
170        sb.AppendFormat("case {0}: {{ ").AppendLine();
171        var rule = ast.Rules.Single(r => r.NtSymbol == ntSymbol.Ident);
172        sb.AppendFormat("return new string[][] {{}}", rule.RuleExpr);
173        sb.AppendLine("break;}}");
174      }
175      foreach (var tSymbol in ast.NonTerminals) {
176
177      }
178      sb.AppendFormat(" else {{ throw new InvalidOperationException(\"Unkown symbol: \"+symbol); }}");
179      sb.AppendLine("}}");
180      sb.AppendFormat("}}").AppendLine();
181
182      // NumberOfAlternatives
183      sb.AppendFormat(
184        "public static int NumberOfAlternatives(string symbol) {{ return GetAlternatives(symbol).Count(); }}").AppendLine();
185      return sb.ToString();
186    }
187
188    // produces helper methods for the attributes of all terminal nodes
189    private string GenerateConstraintMethods(List<SymbolNode> symbols) {
190      var sb = new StringBuilder();
191      var terminals = symbols.OfType<TerminalNode>();
192      foreach (var t in terminals) {
193        sb.AppendLine(GenerateConstraintMethods(t));
194      }
195      return sb.ToString();
196    }
197
198    // generates helper methods for the attributes of a given terminal node
199    private string GenerateConstraintMethods(TerminalNode t) {
200      var sb = new StringBuilder();
201      foreach (var c in t.Constraints) {
202        var fieldType = t.FieldDefinitions.First(d => d.Identifier == c.Ident).Type;
203        if (c.Type == ConstraintNodeType.Range) {
204          sb.AppendFormat("public {0} GetMax{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMaxExpression).AppendLine();
205          sb.AppendFormat("public {0} GetMin{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMinExpression).AppendLine();
206        } else if (c.Type == ConstraintNodeType.Set) {
207          sb.AppendFormat("public {0}[] GetAllowed{1}_{2}() {{ return {3}.ToArray(); }}", fieldType, t.Ident, c.Ident, c.SetExpression).AppendLine();
208        }
209        sb.AppendFormat("public {0} Get{1}_{2}Element(int i) {{ return GetAllowed{1}_{2}()[i]; }}", fieldType, t.Ident, c.Ident);
210      }
211      return sb.ToString();
212    }
213
214
215    // generates code for a breath-first-search generating all possible paths through the grammar
216    private string GeneratePathGeneratorCode(GPDefNode ast) {
217      var sb = new StringBuilder();
218      foreach (var s in ast.NonTerminals) {
219        sb.Append(GeneratePathGeneratorCode(s));
220      }
221      foreach (var s in ast.Terminals) {
222        sb.Append(GeneratePathGeneratorCode(s));
223      }
224      return sb.ToString();
225    }
226
227    // generates code for a breath-first-search generating all possible paths through the grammar
228    private string GeneratePathGeneratorCode(SymbolNode s) {
229      var sb = new StringBuilder();
230
231      return sb.ToString();
232    }
233
234    private string GenerateInterpreterSource(GPDefNode definition) {
235      var sb = new StringBuilder();
236      // create a grammar instance based on the AST
237      var g = new Grammar(definition.NonTerminals, definition.Terminals, definition.Rules);
238      // find formal parameters of root node
239      string formalParameter = definition.NonTerminals.Single(nt => nt.Ident == g.RootSymbol).FormalParameters;
240      // actual parameter are the same as formalparameter only without type identifier
241      var actualParameterEnumerable =
242        Util.ExtractFormalParameters(formalParameter).Select(e => e.RefOrOut + " " + e.Identifier);
243      string actualParameter = string.Empty;
244      // generate a string of actual parameters beginning with: ', a0, a1, ...'
245      if (actualParameterEnumerable.Any()) {
246        foreach (var e in actualParameterEnumerable) {
247          actualParameter += ", " + e;
248        }
249      }
250      // generate entry method for evaluation. This is called from the min/max function
251      // e.g.: ProgramRoot(ref int a0) { ProgramRoot(rootNode , ref a0); }
252      sb.AppendFormat("void {0}({1}) {{ {0}(currentPath {2}); }}", g.RootSymbol, formalParameter, actualParameter).AppendLine();
253
254      // generate methods for all nonterminals and terminals using the grammar instance
255      foreach (var s in definition.NonTerminals) {
256        sb.AppendLine(GenerateInterpreterMethod(g, s));
257      }
258      foreach (var s in definition.Terminals) {
259        sb.AppendLine(GenerateTerminalInterpreterMethod((TerminalNode)s));
260      }
261      return sb.ToString();
262    }
263
264    private string GenerateTerminalInterpreterMethod(TerminalNode s) {
265      var sb = new StringBuilder();
266      // if the terminal symbol has attributes then we must create values for these attributes
267      if (!s.FormalParameters.Any())
268        sb.AppendFormat("private void {0}(IEnumerator<int> path) {{", s.Ident);
269      else
270        sb.AppendFormat("private void {0}(IEnumerator<int> path, {1}) {{", s.Ident, s.FormalParameters);
271
272      // each field must match a formal parameter, assign a value for each parameter
273      foreach (var element in s.FieldDefinitions) {
274        // read next symbol
275        sb.AppendLine("path.MoveNext();");
276        sb.AppendFormat("{0} = Get{1}_{0}Element(path.Current)", element.Identifier, s.Ident).AppendLine(";");
277      }
278      sb.AppendLine("}");
279      return sb.ToString();
280    }
281
282    private string GenerateInterpreterMethod(Grammar g, SymbolNode s) {
283      var sb = new StringBuilder();
284      if (!s.FormalParameters.Any())
285        sb.AppendFormat("private void {0}(IEnumerator<int> path) {{", s.Ident);
286      else
287        sb.AppendFormat("private void {0}(IEnumerator<int> path, {1}) {{", s.Ident, s.FormalParameters);
288      // generate local definitions
289      sb.AppendLine(g.GetLocalDefinitions(s.Ident));
290
291      // read next symbol
292      sb.AppendLine("path.MoveNext();");
293
294      // if there are alternatives for this symbol -> choose alternative based on the path
295      var alts = g.GetAlternatives(s.Ident);
296      if (alts.Count() > 1) {
297        int i = 0;
298        sb.AppendLine("switch(path.Current) {");
299        // generate a case for each alternative
300        foreach (var l in alts) {
301          sb.AppendFormat("case {0}: {{ ", i).AppendLine();
302          foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, i++)) {
303            sb.AppendLine(GenerateSourceForAction(e));
304          }
305          sb.AppendLine("break;").AppendLine("}");
306        }
307        sb.AppendLine("} else throw new System.InvalidOperationException()").AppendLine();
308      } else {
309        foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, 0)) {
310          sb.AppendLine(GenerateSourceForAction(e));
311        }
312      }
313      sb.AppendLine("}");
314      return sb.ToString();
315    }
316
317    // helper for generating calls to other symbol methods
318    private string GenerateSourceForAction(RuleExprNode e) {
319      var action = e as RuleActionNode;
320      var call = e as CallSymbolNode;
321      if (action != null) {
322        return action.SrcCode + ";";
323      } else if (call != null) {
324        if (!call.ActualParameter.Any())
325          return string.Format("{0}(path);", call.Ident);
326        else
327          return string.Format("{0}(path, {1});", call.Ident, call.ActualParameter);
328      } else {
329        throw new ArgumentException();
330      }
331    }
332  }
333}
Note: See TracBrowser for help on using the repository browser.