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

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

#2026 removed unused files

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