source: branches/HeuristicLab.Problems.GPDL/HeuristicLab.Problems.GPDL/3.4/ProblemGenerator.cs @ 9846

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

#2026 added lawn mower problem. create a OSGA for solving the compiled problem directly

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