Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GPDL.Backend/HeuristicLab.Problems.GPDL.CodeGen/3.4/ProblemGenerator.cs @ 16914

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

#2026 created a separate plugin for the classes for the GPDL code generation backend. To remove references to HL code from the core compiler code.

File size: 28.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 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.CodeDom.Compiler;
24using System.Collections.Generic;
25using System.IO;
26using System.Linq;
27using System.Text;
28using HeuristicLab.Optimization;
29using Microsoft.CSharp;
30
31namespace HeuristicLab.Problems.GPDL.CodeGen {
32public class ProblemGenerator {
33  #region templates
34
35  private string usings = @"
36using HeuristicLab.Common;
37using HeuristicLab.Core;
38using HeuristicLab.Data;
39using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
40using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
41using HeuristicLab.Random;
42using HeuristicLab.PluginInfrastructure;
43using HeuristicLab.Optimization;
44using HeuristicLab.Optimization.Operators;
45using HeuristicLab.Operators;
46using HeuristicLab.Parameters;
47using System.Collections.Generic;
48using System.Linq;
49using System;
50using System.Threading;
51using HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm;
52using HeuristicLab.SequentialEngine;
53using HeuristicLab.Selection;
54";
55
56  private string problemClassTemplate = @"
57namespace ?PROBLEMNAME? {
58  [StorableClass]
59  [Item(""?IDENT?Problem"", """")]
60  public sealed class ?IDENT?Problem : SingleObjectiveHeuristicOptimizationProblem<?IDENT?Evaluator, ISymbolicExpressionTreeCreator> {
61    public new ?IDENT?Evaluator Evaluator {
62      get { return (?IDENT?Evaluator)base.Evaluator; }
63      set { base.Evaluator = value; }
64    }
65    public IValueParameter<ISymbolicExpressionGrammar> GrammarParameter {
66      get { return (IValueParameter<ISymbolicExpressionGrammar>)Parameters[""SymbolicExpressionTreeGrammar""]; }
67    }
68
69    [Storable]
70    public ISymbolicExpressionGrammar Grammar { get { return GrammarParameter.Value; } }
71
72    [StorableConstructor]
73    private ?IDENT?Problem(bool deserializing) : base(deserializing) {
74       Initialize();
75    }
76    private ?IDENT?Problem(?IDENT?Problem original, Cloner cloner) : base(original, cloner) {
77      Initialize();
78    }
79    public ?IDENT?Problem() {
80      Parameters.Add(new ValueParameter<ISymbolicExpressionGrammar>(""SymbolicExpressionTreeGrammar"", new ?IDENT?Grammar(this)));
81      Parameters.Add(new FixedValueParameter<IntValue>(""MaximumSymbolicExpressionTreeDepth"", new IntValue(15)));
82      Parameters.Add(new FixedValueParameter<IntValue>(""MaximumSymbolicExpressionTreeLength"", new IntValue(100)));
83      Parameters.Add(new FixedValueParameter<IntValue>(""MaximumFunctionDefinitions"", new IntValue(0)));
84      Parameters.Add(new FixedValueParameter<IntValue>(""MaximumFunctionArguments"", new IntValue(0)));
85      Parameters[""MaximumFunctionDefinitions""].Hidden = true;
86      Parameters[""MaximumFunctionArguments""].Hidden = true;
87      Initialize();
88
89      Evaluator = new ?IDENT?Evaluator(this);
90      SolutionCreator = new ProbabilisticTreeCreator();
91
92 
93      Maximization.Value = Evaluator.Maximization;
94      MaximizationParameter.Hidden = true;
95   
96      InitializeOperators();
97    }   
98
99    private void Initialize() {
100      ?INITCODE?
101    }
102
103    private void InitializeOperators() {
104      Operators.AddRange(ApplicationManager.Manager.GetInstances<ISymbolicExpressionTreeOperator>());
105      Operators.Add(new SymbolicExpressionSymbolFrequencyAnalyzer());
106      Operators.Add(new MinAverageMaxSymbolicExpressionTreeLengthAnalyzer());
107      Operators.Add(new SymbolicExpressionTreeLengthAnalyzer());
108      Operators.Add(new BestSymbolicExpressionTreeAnalyzer());
109      ParameterizeOperators();
110    }
111    private void ParameterizeOperators() {
112      var operators = Parameters.OfType<IValueParameter>().Select(p => p.Value).OfType<IOperator>().Union(Operators).ToList();
113
114      foreach (var op in operators.OfType<ISymbolicExpressionTreeGrammarBasedOperator>()) {
115        op.SymbolicExpressionTreeGrammarParameter.ActualName = GrammarParameter.Name;
116      }
117      foreach (var op in operators.OfType<ISymbolicExpressionTreeSizeConstraintOperator>()) {
118        op.MaximumSymbolicExpressionTreeDepthParameter.ActualName = ""MaximumSymbolicExpressionTreeDepth"";
119        op.MaximumSymbolicExpressionTreeLengthParameter.ActualName = ""MaximumSymbolicExpressionTreeLength"";
120      }
121      foreach (var op in operators.OfType<ISymbolicExpressionTreeArchitectureAlteringOperator>()) {
122        op.MaximumFunctionArgumentsParameter.ActualName = ""MaximumFunctionArguments"";
123        op.MaximumFunctionDefinitionsParameter.ActualName = ""MaximumFunctionDefinitions"";
124      }
125      foreach (var op in operators.OfType<ISymbolicExpressionTreeCrossover>()) {
126        op.ParentsParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
127        op.ChildParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
128      }
129      foreach (var op in operators.OfType<ISymbolicExpressionTreeManipulator>()) {
130        op.SymbolicExpressionTreeParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
131      }
132      foreach (var op in operators.OfType<ISymbolicExpressionTreeAnalyzer>()) {
133        op.SymbolicExpressionTreeParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
134      }
135      foreach(var op in operators.OfType<BestSymbolicExpressionTreeAnalyzer>()) {
136        op.QualityParameter.ActualName = Evaluator.QualityParameter.Name;
137      }
138    }
139
140
141    public override IDeepCloneable Clone(Cloner cloner) {
142      return new ?IDENT?Problem(this, cloner);
143    }
144
145    public double Calculate(ISymbolicExpressionTree solution) {
146      InitSymbolStream(solution);
147      try {
148      ?FITNESSFUNCTION?
149      } catch(Exception e) {
150        var formatter = new SymbolicExpressionTreeStringFormatter();
151        Console.WriteLine(formatter.Format(solution));
152        throw;
153      }
154    }
155
156    ?ADDITIONALCODE?
157
158    private ISymbolicExpressionTreeNode rootNode;
159    private void InitSymbolStream(ISymbolicExpressionTree solution) {   
160      this.rootNode =  solution.Root.GetSubtree(0).GetSubtree(0);
161    }
162
163    ?INTERPRETERSOURCE?
164
165    ?CONSTRAINTSSOURCE?
166  }
167}";
168
169  private string symbolClassTemplate = @"
170namespace ?PROBLEMNAME? {
171  [StorableClass]
172  [Item(""?IDENT?"", """")]
173  public sealed class ?IDENT? : Symbol {
174    public override int MinimumArity {
175      get { return 0; }
176    }
177    public override int MaximumArity {
178      get { return byte.MaxValue; }
179    }
180
181    internal ?PROBLEMNAME?Problem problem;
182
183    [StorableConstructor]
184    private ?IDENT?(bool deserializing) : base(deserializing) { }
185    private ?IDENT?(?IDENT? original, Cloner cloner) : base(original, cloner) {
186      this.problem = original.problem;
187    }
188    public override IDeepCloneable Clone(Cloner cloner) {
189      return new ?IDENT?(this, cloner);
190    }
191    public ?IDENT?(?PROBLEMNAME?Problem problem) : base(""?IDENT?"", string.Empty) {
192      this.problem = problem;
193    }
194  }
195}";
196
197  private string terminalSymbolClassTemplate = @"
198namespace ?PROBLEMNAME? {
199  [StorableClass]
200  [Item(""?IDENT?"", """")]
201  public sealed class ?IDENT? : Symbol {
202    public override int MinimumArity {
203      get { return 0; }
204    }
205    public override int MaximumArity {
206      get { return 0; }
207    }
208
209    internal ?PROBLEMNAME?Problem problem;
210
211    [StorableConstructor]
212    private ?IDENT?(bool deserializing) : base(deserializing) { }
213    private ?IDENT?(?IDENT? original, Cloner cloner) : base(original, cloner) {
214      this.problem = original.problem;
215    }
216    public override IDeepCloneable Clone(Cloner cloner) {
217      return new ?IDENT?(this, cloner);
218    }
219    public ?IDENT?(?PROBLEMNAME?Problem problem) : base(""?IDENT?"", string.Empty) {
220      this.problem = problem;
221    }
222    public override ISymbolicExpressionTreeNode CreateTreeNode() {
223      return new ?IDENT?TreeNode(this);
224    }
225  }
226}";
227
228  private string treeNodeClassTemplate = @"
229namespace ?PROBLEMNAME? {
230  [StorableClass]
231  public sealed class ?IDENT?TreeNode : SymbolicExpressionTreeTerminalNode {
232    public new ?IDENT? Symbol {
233      get { return (?IDENT?)base.Symbol; }
234    }
235
236    ?FIELDS?
237
238    [StorableConstructor]
239    private ?IDENT?TreeNode(bool deserializing) : base(deserializing) { }
240    private ?IDENT?TreeNode(?IDENT?TreeNode original, Cloner cloner)
241      : base(original, cloner) {
242      ?CLONECODE?
243    }
244    public ?IDENT?TreeNode(?IDENT? symbol) : base(symbol) { }
245
246    public override bool HasLocalParameters {
247      get { return true; }
248    }
249
250    public override void ResetLocalParameters(IRandom random) {
251      base.ResetLocalParameters(random);
252      ?RESETFIELDSCODE?
253    }
254
255    public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
256      base.ShakeLocalParameters(random, shakingFactor);
257      ?SHAKEFIELDSCODE?
258    }
259
260    public override IDeepCloneable Clone(Cloner cloner) {
261      return new ?IDENT?TreeNode(this, cloner);
262    }   
263  }
264}";
265
266  private string grammarClassTemplate = @"
267namespace ?PROBLEMNAME? {
268  [NonDiscoverableType]
269  [StorableClass]
270  [Item(""?IDENT?Grammar"", """")]
271  public class ?IDENT?Grammar : SymbolicExpressionGrammar {
272    [StorableConstructor]
273    protected ?IDENT?Grammar(bool deserializing) : base(deserializing) { }
274    protected ?IDENT?Grammar(?IDENT?Grammar original, Cloner cloner) : base(original, cloner) { }
275    public ?IDENT?Grammar(?IDENT?Problem problem)
276      : base(ItemAttribute.GetName(typeof(?IDENT?Grammar)), ItemAttribute.GetDescription(typeof(?IDENT?Grammar))) {
277      Initialize(problem);
278    }
279    public override IDeepCloneable Clone(Cloner cloner) {
280      return new ?IDENT?Grammar(this, cloner);
281    }
282
283    private void Initialize(?IDENT?Problem problem) {
284      ?CREATESYMBOLS?
285      var rootSymbol = ?ROOTSYMBOL?;
286
287      ?SETSUBTREECOUNTS?
288
289      // set start symbol
290      AddAllowedChildSymbol(StartSymbol, rootSymbol);
291
292      ?SETALLOWEDSUBTREECOUNTS?
293    }
294  }
295}
296";
297  private string evaluatorClassTemplate = @"
298namespace ?PROBLEMNAME? {
299  [StorableClass]
300  [Item(""?IDENT?Evaluator"", """")] 
301  public class ?IDENT?Evaluator : SingleSuccessorOperator, ISingleObjectiveEvaluator {
302    private const string SymbolicExpressionTreeParameterName = ""SymbolicExpressionTree"";
303    private const string QualityParameterName = ""Quality"";
304
305    public override bool CanChangeName { get { return false; } }
306
307    #region parameter properties
308    public ILookupParameter<ISymbolicExpressionTree> SymbolicExpressionTreeParameter {
309      get { return (ILookupParameter<ISymbolicExpressionTree>)Parameters[SymbolicExpressionTreeParameterName]; }
310    }
311    public ILookupParameter<DoubleValue> QualityParameter {
312      get { return (ILookupParameter<DoubleValue>)Parameters[QualityParameterName]; }
313    }
314    #endregion
315    public bool Maximization { get { return ?MAXIMIZATION?; }  }
316
317    public ?IDENT?Problem problem;
318
319    [StorableConstructor]
320    protected ?IDENT?Evaluator(bool deserializing) : base(deserializing) { }
321    protected ?IDENT?Evaluator(?IDENT?Evaluator original, Cloner cloner)
322      : base(original, cloner) {
323      this.problem = original.problem;
324    }
325    public ?IDENT?Evaluator(?IDENT?Problem problem)
326      : base() {
327      Parameters.Add(new LookupParameter<ISymbolicExpressionTree>(SymbolicExpressionTreeParameterName));
328      Parameters.Add(new LookupParameter<DoubleValue>(QualityParameterName));
329      this.problem = problem;
330    }
331    [StorableHook(HookType.AfterDeserialization)]
332    private void AfterDeserialization() {
333    }
334    public override IDeepCloneable Clone(Cloner cloner) {
335      return new ?IDENT?Evaluator(this, cloner);
336    }
337
338    public override IOperation Apply() {
339      var solution = SymbolicExpressionTreeParameter.ActualValue;
340      double quality = problem.Calculate(solution);
341      QualityParameter.ActualValue = new DoubleValue(quality);
342      return base.Apply();
343    }
344  }
345}
346";
347  #endregion
348
349  private StringBuilder problemSourceCode;
350
351  public ProblemGenerator() {
352    problemSourceCode = new StringBuilder();
353  }
354
355  public ISingleObjectiveHeuristicOptimizationProblem GenerateFromAst(GPDefNode definition) {
356    problemSourceCode.AppendLine(usings);
357
358    GenerateSymbols(definition.NonTerminals);
359    GenerateSymbols(definition.Terminals);
360
361    GenerateTreeNodes(definition.Terminals);
362    GenerateGrammar(definition);
363
364    GenerateEvaluator(definition);
365    GenerateProblem(definition);
366
367    problemSourceCode.Replace("?PROBLEMNAME?", definition.Name);
368
369    // write to a file for debugging
370    using (var stream = new StreamWriter(definition.Name + ".cs")) {
371      stream.WriteLine(problemSourceCode.ToString());
372    }
373
374    // compile generated source
375    using (var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } })) {
376      var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll", "System.dll", "System.Drawing.dll" }, Path.ChangeExtension(Path.GetRandomFileName(), ".dll"), true);
377      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Common-3.3.dll");
378      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Common.Resources-3.3.dll");
379      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Core-3.3.dll");
380      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Data-3.3.dll");
381      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.dll");
382      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Random-3.3.dll");
383      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Persistence-3.3.dll");
384      parameters.ReferencedAssemblies.Add(@"HeuristicLab.PluginInfrastructure-3.3.dll");
385      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Optimization-3.3.dll");
386      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Optimization.Operators-3.3.dll");
387      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Operators-3.3.dll");
388      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Collections-3.3.dll");
389      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Parameters-3.3.dll");
390      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Problems.DataAnalysis-3.4.dll");
391      parameters.ReferencedAssemblies.Add(@"ALGLIB-3.7.0.dll");
392      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Problems.Instances-3.3.dll");
393      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Problems.Instances.DataAnalysis-3.3.dll");
394      parameters.ReferencedAssemblies.Add(@"HeuristicLab.SequentialEngine-3.3.dll");
395      parameters.ReferencedAssemblies.Add(@"HeuristicLab.ParallelEngine-3.3.dll");
396      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Algorithms.GeneticAlgorithm-3.3.dll");
397      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm-3.3.dll");
398      parameters.ReferencedAssemblies.Add(@"HeuristicLab.Selection-3.3.dll");
399
400      CompilerResults results = csc.CompileAssemblyFromSource(parameters, problemSourceCode.ToString());
401      results.Errors.Cast<CompilerError>()
402        .ToList()
403        .ForEach(error => Console.WriteLine(error.Line + " " + error.ErrorText));
404
405      // load the assembly, and create an instance from the generate problem class
406      var asm = results.CompiledAssembly;
407      AppDomain.CurrentDomain.Load(asm.GetName());
408      var problem = Activator.CreateInstance(asm.FullName, definition.Name + "." + definition.Name + "Problem").Unwrap();
409      return (ISingleObjectiveHeuristicOptimizationProblem)problem;
410    }
411  }
412
413
414
415  private void GenerateEvaluator(GPDefNode definition) {
416    var evaluatorClassCode =
417      evaluatorClassTemplate
418        .Replace("?IDENT?", definition.Name)
419        .Replace("?MAXIMIZATION?", definition.FitnessFunctionNode.Maximization ? "true" : "false");
420    problemSourceCode.AppendLine(evaluatorClassCode).AppendLine();
421  }
422
423  private void GenerateProblem(GPDefNode definition) {
424    var problemClassCode =
425      problemClassTemplate
426        .Replace("?IDENT?", definition.Name)
427        .Replace("?FITNESSFUNCTION?", definition.FitnessFunctionNode.SrcCode)
428        .Replace("?INTERPRETERSOURCE?", GenerateInterpreterSource(definition))
429        .Replace("?INITCODE?", definition.InitCodeNode.SrcCode)
430        .Replace("?ADDITIONALCODE?", definition.ClassCodeNode.SrcCode)
431        .Replace("?CONSTRAINTSSOURCE?", GenerateConstraintMethods(definition.Terminals));
432
433    problemSourceCode.AppendLine(problemClassCode).AppendLine();
434  }
435
436  private string GenerateConstraintMethods(List<SymbolNode> symbols) {
437    var sb = new StringBuilder();
438    var terminals = symbols.OfType<TerminalNode>();
439    foreach (var t in terminals) {
440      sb.AppendLine(GenerateConstraintMethods(t));
441    }
442    return sb.ToString();
443  }
444
445  private string GenerateConstraintMethods(TerminalNode t) {
446    var sb = new StringBuilder();
447    foreach (var c in t.Constraints) {
448      var fieldType = t.FieldDefinitions.First(d => d.Identifier == c.Ident).Type;
449      if (c.Type == ConstraintNodeType.Range) {
450        sb.AppendFormat("public {0} GetMax{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMaxExpression).AppendLine();
451        sb.AppendFormat("public {0} GetMin{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMinExpression).AppendLine();
452      } else if (c.Type == ConstraintNodeType.Set) {
453        sb.AppendFormat("public IEnumerable<{0}> GetAllowed{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.SetExpression).AppendLine();
454      }
455    }
456    return sb.ToString();
457  }
458
459  private string GenerateInterpreterSource(GPDefNode definition) {
460    var sb = new StringBuilder();
461    var g = new Grammar(definition.NonTerminals, definition.Terminals, definition.Rules);
462    string formalParameter = definition.NonTerminals.Single(nt => nt.Ident == g.RootSymbol).FormalParameters;
463    var actualParameterEnumerable =
464      Util.ExtractFormalParameters(formalParameter).Select(e => e.RefOrOut + " " + e.Identifier);
465    string actualParameter = string.Empty;
466    if (actualParameterEnumerable.Any()) {
467      foreach (var e in actualParameterEnumerable) {
468        actualParameter += ", " + e;
469      }
470    }
471    sb.AppendFormat("void {0}({1}) {{ {0}(rootNode {2}); }}", g.RootSymbol, formalParameter, actualParameter).AppendLine();
472
473    foreach (var s in definition.NonTerminals) {
474      sb.AppendLine(GenerateInterpreterMethod(g, s));
475    }
476    foreach (var s in definition.Terminals) {
477      sb.AppendLine(GenerateTerminalInterpreterMethod((TerminalNode)s));
478    }
479    return sb.ToString();
480  }
481
482  private string GenerateTerminalInterpreterMethod(TerminalNode s) {
483    var sb = new StringBuilder();
484    if (!s.FormalParameters.Any())
485      sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree) {{", s.Ident);
486    else
487      sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree, {1}) {{", s.Ident, s.FormalParameters);
488    sb.AppendFormat("if (tree.Symbol == null || tree.Symbol.Name != \"{0}\") throw new InvalidOperationException();", s.Ident).AppendLine();
489    sb.AppendFormat("var cur = ({0}TreeNode)tree;", s.Ident).AppendLine();
490    foreach (var element in s.FieldDefinitions) {
491      sb.AppendFormat("{0} = cur.{0}", element.Identifier).AppendLine(";");
492    }
493    sb.AppendLine("}");
494    return sb.ToString();
495  }
496
497  private string GenerateInterpreterMethod(Grammar g, SymbolNode s) {
498    var sb = new StringBuilder();
499    if (!s.FormalParameters.Any())
500      sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree) {{", s.Ident);
501    else
502      sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree, {1}) {{", s.Ident, s.FormalParameters);
503    sb.AppendLine(g.GetLocalDefinitions(s.Ident));
504    sb.AppendFormat("ISymbolicExpressionTreeNode subtree = null;").AppendLine();
505    sb.AppendFormat("if (tree.Symbol== null || tree.Symbol.Name != \"{0}\") throw new InvalidOperationException();", s.Ident).AppendLine();
506    var alts = g.GetAlternatives(s.Ident);
507    var lookahead = alts.Select(seq => seq.First());
508    if (lookahead.Count() > 1) {
509      sb.AppendLine("System.Diagnostics.Debug.Assert(tree.SubtreeCount == 1);");
510      sb.AppendLine("subtree = tree.GetSubtree(0);");
511      int i = 0;
512      sb.AppendFormat("if(subtree.Symbol.Name == \"{0}\") {{ ", lookahead.First()).AppendLine();
513      foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, i++)) {
514        sb.AppendLine(GenerateSourceForAction(e));
515      }
516      foreach (var l in lookahead.Skip(1)) {
517        sb.AppendFormat("}} else if(subtree.Symbol.Name == \"{0}\") {{ ", l).AppendLine();
518        foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, i++)) {
519          sb.AppendLine(GenerateSourceForAction(e));
520        }
521      }
522      sb.AppendFormat("}} else throw new System.InvalidOperationException(\"In {0} found symbol \"+tree.Symbol.Name+\". Expected one of: {1}\");", s.Ident, lookahead.Aggregate("", (acc, l) => acc + l + " ")).AppendLine();
523    } else {
524      int eIdx = 0;
525      foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, 0)) {
526        if (e is CallSymbolNode) {
527          sb.AppendFormat("subtree = tree.GetSubtree({0});", eIdx++);
528        }
529        sb.AppendLine(GenerateSourceForAction(e));
530      }
531    }
532    sb.AppendLine("}");
533    return sb.ToString();
534  }
535
536  private string GenerateSourceForAction(RuleExprNode e) {
537    var action = e as RuleActionNode;
538    var call = e as CallSymbolNode;
539    if (action != null) {
540      return action.SrcCode + ";";
541    } else if (call != null) {
542      if (!call.ActualParameter.Any())
543        return string.Format("{0}(subtree);", call.Ident);
544      else
545        return string.Format("{0}(subtree, {1});", call.Ident, call.ActualParameter);
546    } else {
547      throw new ArgumentException();
548    }
549  }
550
551  private void GenerateGrammar(GPDefNode definition) {
552    IEnumerable<SymbolNode> ntSymbols = definition.NonTerminals;
553    IEnumerable<SymbolNode> tSymbols = definition.Terminals;
554    List<RuleNode> ruleNodes = definition.Rules;
555    var g = new Grammar(ntSymbols, tSymbols, ruleNodes);
556    Console.WriteLine(g);
557
558    var grammarClassCode =
559      grammarClassTemplate
560        .Replace("?IDENT?", definition.Name)
561        .Replace("?CREATESYMBOLS?", GenerateGrammarSymbolDefinitionSource(g))
562        .Replace("?ROOTSYMBOL?", "_" + g.RootSymbol)
563        .Replace("?SETSUBTREECOUNTS?", GenerateGrammarSubtreeCountDefinitionSource(g))
564        .Replace("?SETALLOWEDSUBTREECOUNTS?", GenerateGrammarAllowedSubtreeDefinitionSource(g));
565
566
567    problemSourceCode.AppendLine(grammarClassCode).AppendLine();
568  }
569
570  private string GenerateGrammarSymbolDefinitionSource(Grammar g) {
571    StringBuilder sb = new StringBuilder();
572    foreach (var sy in g.Symbols) {
573      sb.AppendFormat("var _{0} = new {0}(problem); AddSymbol(_{0});", sy).AppendLine();
574    }
575    return sb.ToString();
576  }
577
578  private string GenerateGrammarSubtreeCountDefinitionSource(Grammar g) {
579    StringBuilder sb = new StringBuilder();
580    foreach (var sy in g.Symbols) {
581      var alt = g.GetAlternatives(sy);
582      if (alt.Count() > 0) {
583        var minSeqLength = alt.Min(seq => seq.Count);
584        var maxSeqLength = alt.Max(seq => seq.Count);
585        sb.AppendFormat("SetSubtreeCount(_{0}, {1}, {2});", sy, maxSeqLength, minSeqLength).AppendLine();
586      } else {
587        sb.AppendFormat("SetSubtreeCount(_{0}, {1}, {2});", sy, 0, 0).AppendLine();
588      }
589    }
590    return sb.ToString();
591  }
592
593  private string GenerateGrammarAllowedSubtreeDefinitionSource(Grammar g) {
594    StringBuilder sb = new StringBuilder();
595    foreach (var sy in g.Symbols) {
596      foreach (var seq in g.GetAlternatives(sy)) {
597        for (int argIdx = 0; argIdx < seq.Count; argIdx++) {
598          var childSy = seq[argIdx];
599          sb.AppendFormat("AddAllowedChildSymbol(_{0}, _{1}, {2});", sy, childSy, argIdx).AppendLine();
600        }
601      }
602    }
603    return sb.ToString();
604  }
605
606  private void GenerateTreeNodes(IEnumerable<SymbolNode> symbols) {
607    foreach (var s in symbols.OfType<TerminalNode>()) {
608      var classCode = treeNodeClassTemplate
609        .Replace("?IDENT?", s.Ident)
610        .Replace("?RESETFIELDSCODE?", GenerateNodeInitSourceCode(s))
611        .Replace("?SHAKEFIELDSCODE?", GenerateNodeUpdateSourceCode(s))
612        ;
613
614      StringBuilder fieldSource = new StringBuilder();
615      StringBuilder cloningSource = new StringBuilder();
616      foreach (var par in s.FieldDefinitions) {
617        fieldSource.AppendLine("[Storable]");
618        fieldSource.Append("internal ").Append(par.Type).Append(" ").Append(par.Identifier).AppendLine(";");
619
620        cloningSource.Append("this.").Append(par.Identifier)
621          .Append("=").Append("(").Append(par.Type).Append(")")
622          .Append("original.").Append(par.Identifier).AppendLine(";");
623
624      }
625
626      classCode = classCode.Replace("?FIELDS?", fieldSource.ToString());
627      classCode = classCode.Replace("?CLONECODE?", cloningSource.ToString());
628
629      problemSourceCode
630        .AppendLine(classCode)
631        .AppendLine();
632    }
633  }
634
635  private string GenerateNodeInitSourceCode(TerminalNode s) {
636    var sb = new StringBuilder();
637    sb.AppendLine("var problem = Symbol.problem;");
638    foreach (var f in s.FieldDefinitions) {
639      var cType = GetConstraintTypeFor(f.Identifier, s.Constraints);
640      if (cType == ConstraintNodeType.Range) {
641        sb.AppendFormat("var max_{1} = problem.GetMax{0}_{1}();", s.Ident, f.Identifier).AppendLine();
642        sb.AppendFormat("var min_{1} = problem.GetMin{0}_{1}();", s.Ident, f.Identifier).AppendLine();
643        sb.AppendFormat("{0} = min_{0} + random.NextDouble() * (max_{0} - min_{0});", f.Identifier).AppendLine();
644      } else if (cType == ConstraintNodeType.Set) {
645        sb.AppendFormat("var set_{1} = problem.GetAllowed{0}_{1}().ToList();", s.Ident, f.Identifier).AppendLine();
646        sb.AppendFormat("{0} = set_{0}[random.Next(set_{0}.Count())];", f.Identifier).AppendLine();
647      }
648    }
649    return sb.ToString();
650  }
651
652  private string GenerateNodeUpdateSourceCode(TerminalNode s) {
653    var sb = new StringBuilder();
654    sb.AppendLine("var problem = Symbol.problem;");
655    foreach (var f in s.FieldDefinitions) {
656      var cType = GetConstraintTypeFor(f.Identifier, s.Constraints);
657      if (cType == ConstraintNodeType.Range) {
658        sb.AppendFormat("var max_{1} = problem.GetMax{0}_{1}();", s.Ident, f.Identifier).AppendLine();
659        sb.AppendFormat("var min_{1} = problem.GetMin{0}_{1}();", s.Ident, f.Identifier).AppendLine();
660        sb.AppendFormat("{0} = min_{0} + random.NextDouble() * (max_{0} - min_{0});", f.Identifier).AppendLine();
661      } else if (cType == ConstraintNodeType.Set) {
662        sb.AppendFormat("var set_{1} = problem.GetAllowed{0}_{1}().ToList();", s.Ident, f.Identifier).AppendLine();
663        sb.AppendFormat("{0} = set_{0}[random.Next(set_{0}.Count())];", f.Identifier).AppendLine();
664      }
665    }
666    return sb.ToString();
667  }
668
669  private ConstraintNodeType GetConstraintTypeFor(string id, IEnumerable<ConstraintNode> contraints) {
670    return contraints.Single(c => c.Ident == id).Type;
671  }
672
673  private void GenerateSymbols(List<SymbolNode> symbols) {
674    foreach (var s in symbols.OfType<NonTerminalNode>()) {
675      problemSourceCode
676        .AppendLine(symbolClassTemplate.Replace("?IDENT?", s.Ident))
677        .AppendLine();
678    }
679    foreach (var s in symbols.OfType<TerminalNode>()) {
680      problemSourceCode
681        .AppendLine(terminalSymbolClassTemplate.Replace("?IDENT?", s.Ident))
682        .AppendLine();
683    }
684  }
685}
686}
Note: See TracBrowser for help on using the repository browser.