#region License Information
/* HeuristicLab
* Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using HeuristicLab.Optimization;
using Microsoft.CSharp;
namespace HeuristicLab.Problems.GPDL.CodeGen {
public class ProblemGenerator {
#region templates
private string usings = @"
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Random;
using HeuristicLab.PluginInfrastructure;
using HeuristicLab.Optimization;
using HeuristicLab.Optimization.Operators;
using HeuristicLab.Operators;
using HeuristicLab.Parameters;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Threading;
using HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm;
using HeuristicLab.SequentialEngine;
using HeuristicLab.Selection;
";
private string problemClassTemplate = @"
namespace ?PROBLEMNAME? {
[StorableClass]
[Item(""?IDENT?Problem"", """")]
public sealed class ?IDENT?Problem : SingleObjectiveHeuristicOptimizationProblem {
public new ?IDENT?Evaluator Evaluator {
get { return (?IDENT?Evaluator)base.Evaluator; }
set { base.Evaluator = value; }
}
public IValueParameter GrammarParameter {
get { return (IValueParameter)Parameters[""SymbolicExpressionTreeGrammar""]; }
}
[Storable]
public ISymbolicExpressionGrammar Grammar { get { return GrammarParameter.Value; } }
[StorableConstructor]
private ?IDENT?Problem(bool deserializing) : base(deserializing) {
Initialize();
}
private ?IDENT?Problem(?IDENT?Problem original, Cloner cloner) : base(original, cloner) {
Initialize();
}
public ?IDENT?Problem() {
Parameters.Add(new ValueParameter(""SymbolicExpressionTreeGrammar"", new ?IDENT?Grammar(this)));
Parameters.Add(new FixedValueParameter(""MaximumSymbolicExpressionTreeDepth"", new IntValue(15)));
Parameters.Add(new FixedValueParameter(""MaximumSymbolicExpressionTreeLength"", new IntValue(100)));
Parameters.Add(new FixedValueParameter(""MaximumFunctionDefinitions"", new IntValue(0)));
Parameters.Add(new FixedValueParameter(""MaximumFunctionArguments"", new IntValue(0)));
Parameters[""MaximumFunctionDefinitions""].Hidden = true;
Parameters[""MaximumFunctionArguments""].Hidden = true;
Initialize();
Evaluator = new ?IDENT?Evaluator(this);
SolutionCreator = new ProbabilisticTreeCreator();
Maximization.Value = Evaluator.Maximization;
MaximizationParameter.Hidden = true;
InitializeOperators();
}
private void Initialize() {
?INITCODE?
}
private void InitializeOperators() {
Operators.AddRange(ApplicationManager.Manager.GetInstances());
Operators.Add(new SymbolicExpressionSymbolFrequencyAnalyzer());
Operators.Add(new MinAverageMaxSymbolicExpressionTreeLengthAnalyzer());
Operators.Add(new SymbolicExpressionTreeLengthAnalyzer());
Operators.Add(new BestSymbolicExpressionTreeAnalyzer());
ParameterizeOperators();
}
private void ParameterizeOperators() {
var operators = Parameters.OfType().Select(p => p.Value).OfType().Union(Operators).ToList();
foreach (var op in operators.OfType()) {
op.SymbolicExpressionTreeGrammarParameter.ActualName = GrammarParameter.Name;
}
foreach (var op in operators.OfType()) {
op.MaximumSymbolicExpressionTreeDepthParameter.ActualName = ""MaximumSymbolicExpressionTreeDepth"";
op.MaximumSymbolicExpressionTreeLengthParameter.ActualName = ""MaximumSymbolicExpressionTreeLength"";
}
foreach (var op in operators.OfType()) {
op.MaximumFunctionArgumentsParameter.ActualName = ""MaximumFunctionArguments"";
op.MaximumFunctionDefinitionsParameter.ActualName = ""MaximumFunctionDefinitions"";
}
foreach (var op in operators.OfType()) {
op.ParentsParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
op.ChildParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
}
foreach (var op in operators.OfType()) {
op.SymbolicExpressionTreeParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
}
foreach (var op in operators.OfType()) {
op.SymbolicExpressionTreeParameter.ActualName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
}
foreach(var op in operators.OfType()) {
op.QualityParameter.ActualName = Evaluator.QualityParameter.Name;
}
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ?IDENT?Problem(this, cloner);
}
public double Calculate(ISymbolicExpressionTree solution) {
InitSymbolStream(solution);
try {
?FITNESSFUNCTION?
} catch(Exception e) {
var formatter = new SymbolicExpressionTreeStringFormatter();
Console.WriteLine(formatter.Format(solution));
throw;
}
}
?ADDITIONALCODE?
private ISymbolicExpressionTreeNode rootNode;
private void InitSymbolStream(ISymbolicExpressionTree solution) {
this.rootNode = solution.Root.GetSubtree(0).GetSubtree(0);
}
?INTERPRETERSOURCE?
?CONSTRAINTSSOURCE?
}
}";
private string symbolClassTemplate = @"
namespace ?PROBLEMNAME? {
[StorableClass]
[Item(""?IDENT?"", """")]
public sealed class ?IDENT? : Symbol {
public override int MinimumArity {
get { return 0; }
}
public override int MaximumArity {
get { return byte.MaxValue; }
}
internal ?PROBLEMNAME?Problem problem;
[StorableConstructor]
private ?IDENT?(bool deserializing) : base(deserializing) { }
private ?IDENT?(?IDENT? original, Cloner cloner) : base(original, cloner) {
this.problem = original.problem;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ?IDENT?(this, cloner);
}
public ?IDENT?(?PROBLEMNAME?Problem problem) : base(""?IDENT?"", string.Empty) {
this.problem = problem;
}
}
}";
private string terminalSymbolClassTemplate = @"
namespace ?PROBLEMNAME? {
[StorableClass]
[Item(""?IDENT?"", """")]
public sealed class ?IDENT? : Symbol {
public override int MinimumArity {
get { return 0; }
}
public override int MaximumArity {
get { return 0; }
}
internal ?PROBLEMNAME?Problem problem;
[StorableConstructor]
private ?IDENT?(bool deserializing) : base(deserializing) { }
private ?IDENT?(?IDENT? original, Cloner cloner) : base(original, cloner) {
this.problem = original.problem;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ?IDENT?(this, cloner);
}
public ?IDENT?(?PROBLEMNAME?Problem problem) : base(""?IDENT?"", string.Empty) {
this.problem = problem;
}
public override ISymbolicExpressionTreeNode CreateTreeNode() {
return new ?IDENT?TreeNode(this);
}
}
}";
private string treeNodeClassTemplate = @"
namespace ?PROBLEMNAME? {
[StorableClass]
public sealed class ?IDENT?TreeNode : SymbolicExpressionTreeTerminalNode {
public new ?IDENT? Symbol {
get { return (?IDENT?)base.Symbol; }
}
?FIELDS?
[StorableConstructor]
private ?IDENT?TreeNode(bool deserializing) : base(deserializing) { }
private ?IDENT?TreeNode(?IDENT?TreeNode original, Cloner cloner)
: base(original, cloner) {
?CLONECODE?
}
public ?IDENT?TreeNode(?IDENT? symbol) : base(symbol) { }
public override bool HasLocalParameters {
get { return true; }
}
public override void ResetLocalParameters(IRandom random) {
base.ResetLocalParameters(random);
?RESETFIELDSCODE?
}
public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
base.ShakeLocalParameters(random, shakingFactor);
?SHAKEFIELDSCODE?
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ?IDENT?TreeNode(this, cloner);
}
}
}";
private string grammarClassTemplate = @"
namespace ?PROBLEMNAME? {
[NonDiscoverableType]
[StorableClass]
[Item(""?IDENT?Grammar"", """")]
public class ?IDENT?Grammar : SymbolicExpressionGrammar {
[StorableConstructor]
protected ?IDENT?Grammar(bool deserializing) : base(deserializing) { }
protected ?IDENT?Grammar(?IDENT?Grammar original, Cloner cloner) : base(original, cloner) { }
public ?IDENT?Grammar(?IDENT?Problem problem)
: base(ItemAttribute.GetName(typeof(?IDENT?Grammar)), ItemAttribute.GetDescription(typeof(?IDENT?Grammar))) {
Initialize(problem);
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ?IDENT?Grammar(this, cloner);
}
private void Initialize(?IDENT?Problem problem) {
?CREATESYMBOLS?
var rootSymbol = ?ROOTSYMBOL?;
?SETSUBTREECOUNTS?
// set start symbol
AddAllowedChildSymbol(StartSymbol, rootSymbol);
?SETALLOWEDSUBTREECOUNTS?
}
}
}
";
private string evaluatorClassTemplate = @"
namespace ?PROBLEMNAME? {
[StorableClass]
[Item(""?IDENT?Evaluator"", """")]
public class ?IDENT?Evaluator : SingleSuccessorOperator, ISingleObjectiveEvaluator {
private const string SymbolicExpressionTreeParameterName = ""SymbolicExpressionTree"";
private const string QualityParameterName = ""Quality"";
public override bool CanChangeName { get { return false; } }
#region parameter properties
public ILookupParameter SymbolicExpressionTreeParameter {
get { return (ILookupParameter)Parameters[SymbolicExpressionTreeParameterName]; }
}
public ILookupParameter QualityParameter {
get { return (ILookupParameter)Parameters[QualityParameterName]; }
}
#endregion
public bool Maximization { get { return ?MAXIMIZATION?; } }
public ?IDENT?Problem problem;
[StorableConstructor]
protected ?IDENT?Evaluator(bool deserializing) : base(deserializing) { }
protected ?IDENT?Evaluator(?IDENT?Evaluator original, Cloner cloner)
: base(original, cloner) {
this.problem = original.problem;
}
public ?IDENT?Evaluator(?IDENT?Problem problem)
: base() {
Parameters.Add(new LookupParameter(SymbolicExpressionTreeParameterName));
Parameters.Add(new LookupParameter(QualityParameterName));
this.problem = problem;
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
}
public override IDeepCloneable Clone(Cloner cloner) {
return new ?IDENT?Evaluator(this, cloner);
}
public override IOperation Apply() {
var solution = SymbolicExpressionTreeParameter.ActualValue;
double quality = problem.Calculate(solution);
QualityParameter.ActualValue = new DoubleValue(quality);
return base.Apply();
}
}
}
";
#endregion
private StringBuilder problemSourceCode;
public ProblemGenerator() {
problemSourceCode = new StringBuilder();
}
public ISingleObjectiveHeuristicOptimizationProblem GenerateFromAst(GPDefNode definition) {
problemSourceCode.AppendLine(usings);
GenerateSymbols(definition.NonTerminals);
GenerateSymbols(definition.Terminals);
GenerateTreeNodes(definition.Terminals);
GenerateGrammar(definition);
GenerateEvaluator(definition);
GenerateProblem(definition);
problemSourceCode.Replace("?PROBLEMNAME?", definition.Name);
// write to a file for debugging
using (var stream = new StreamWriter(definition.Name + ".cs")) {
stream.WriteLine(problemSourceCode.ToString());
}
// compile generated source
using (var csc = new CSharpCodeProvider(new Dictionary() { { "CompilerVersion", "v4.0" } })) {
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll", "System.dll", "System.Drawing.dll" }, Path.ChangeExtension(Path.GetRandomFileName(), ".dll"), true);
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Common-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Common.Resources-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Core-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Data-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Random-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Persistence-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.PluginInfrastructure-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Optimization-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Optimization.Operators-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Operators-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Collections-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Parameters-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Problems.DataAnalysis-3.4.dll");
parameters.ReferencedAssemblies.Add(@"ALGLIB-3.7.0.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Problems.Instances-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Problems.Instances.DataAnalysis-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.SequentialEngine-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.ParallelEngine-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Algorithms.GeneticAlgorithm-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm-3.3.dll");
parameters.ReferencedAssemblies.Add(@"HeuristicLab.Selection-3.3.dll");
CompilerResults results = csc.CompileAssemblyFromSource(parameters, problemSourceCode.ToString());
results.Errors.Cast()
.ToList()
.ForEach(error => Console.WriteLine(error.Line + " " + error.ErrorText));
// load the assembly, and create an instance from the generate problem class
var asm = results.CompiledAssembly;
AppDomain.CurrentDomain.Load(asm.GetName());
var problem = Activator.CreateInstance(asm.FullName, definition.Name + "." + definition.Name + "Problem").Unwrap();
return (ISingleObjectiveHeuristicOptimizationProblem)problem;
}
}
private void GenerateEvaluator(GPDefNode definition) {
var evaluatorClassCode =
evaluatorClassTemplate
.Replace("?IDENT?", definition.Name)
.Replace("?MAXIMIZATION?", definition.FitnessFunctionNode.Maximization ? "true" : "false");
problemSourceCode.AppendLine(evaluatorClassCode).AppendLine();
}
private void GenerateProblem(GPDefNode definition) {
var problemClassCode =
problemClassTemplate
.Replace("?IDENT?", definition.Name)
.Replace("?FITNESSFUNCTION?", definition.FitnessFunctionNode.SrcCode)
.Replace("?INTERPRETERSOURCE?", GenerateInterpreterSource(definition))
.Replace("?INITCODE?", definition.InitCodeNode.SrcCode)
.Replace("?ADDITIONALCODE?", definition.ClassCodeNode.SrcCode)
.Replace("?CONSTRAINTSSOURCE?", GenerateConstraintMethods(definition.Terminals));
problemSourceCode.AppendLine(problemClassCode).AppendLine();
}
private string GenerateConstraintMethods(List symbols) {
var sb = new StringBuilder();
var terminals = symbols.OfType();
foreach (var t in terminals) {
sb.AppendLine(GenerateConstraintMethods(t));
}
return sb.ToString();
}
private string GenerateConstraintMethods(TerminalNode t) {
var sb = new StringBuilder();
foreach (var c in t.Constraints) {
var fieldType = t.FieldDefinitions.First(d => d.Identifier == c.Ident).Type;
if (c.Type == ConstraintNodeType.Range) {
sb.AppendFormat("public {0} GetMax{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMaxExpression).AppendLine();
sb.AppendFormat("public {0} GetMin{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMinExpression).AppendLine();
} else if (c.Type == ConstraintNodeType.Set) {
sb.AppendFormat("public IEnumerable<{0}> GetAllowed{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.SetExpression).AppendLine();
}
}
return sb.ToString();
}
private string GenerateInterpreterSource(GPDefNode definition) {
var sb = new StringBuilder();
var g = new Grammar(definition.NonTerminals, definition.Terminals, definition.Rules);
string formalParameter = definition.NonTerminals.Single(nt => nt.Ident == g.RootSymbol).FormalParameters;
var actualParameterEnumerable =
Util.ExtractFormalParameters(formalParameter).Select(e => e.RefOrOut + " " + e.Identifier);
string actualParameter = string.Empty;
if (actualParameterEnumerable.Any()) {
foreach (var e in actualParameterEnumerable) {
actualParameter += ", " + e;
}
}
sb.AppendFormat("void {0}({1}) {{ {0}(rootNode {2}); }}", g.RootSymbol, formalParameter, actualParameter).AppendLine();
foreach (var s in definition.NonTerminals) {
sb.AppendLine(GenerateInterpreterMethod(g, s));
}
foreach (var s in definition.Terminals) {
sb.AppendLine(GenerateTerminalInterpreterMethod((TerminalNode)s));
}
return sb.ToString();
}
private string GenerateTerminalInterpreterMethod(TerminalNode s) {
var sb = new StringBuilder();
if (!s.FormalParameters.Any())
sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree) {{", s.Ident);
else
sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree, {1}) {{", s.Ident, s.FormalParameters);
sb.AppendFormat("if (tree.Symbol == null || tree.Symbol.Name != \"{0}\") throw new InvalidOperationException();", s.Ident).AppendLine();
sb.AppendFormat("var cur = ({0}TreeNode)tree;", s.Ident).AppendLine();
foreach (var element in s.FieldDefinitions) {
sb.AppendFormat("{0} = cur.{0}", element.Identifier).AppendLine(";");
}
sb.AppendLine("}");
return sb.ToString();
}
private string GenerateInterpreterMethod(Grammar g, SymbolNode s) {
var sb = new StringBuilder();
if (!s.FormalParameters.Any())
sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree) {{", s.Ident);
else
sb.AppendFormat("private void {0}(ISymbolicExpressionTreeNode tree, {1}) {{", s.Ident, s.FormalParameters);
sb.AppendLine(g.GetLocalDefinitions(s.Ident));
sb.AppendFormat("ISymbolicExpressionTreeNode subtree = null;").AppendLine();
sb.AppendFormat("if (tree.Symbol== null || tree.Symbol.Name != \"{0}\") throw new InvalidOperationException();", s.Ident).AppendLine();
var alts = g.GetAlternatives(s.Ident);
var lookahead = alts.Select(seq => seq.First());
if (lookahead.Count() > 1) {
sb.AppendLine("System.Diagnostics.Debug.Assert(tree.SubtreeCount == 1);");
sb.AppendLine("subtree = tree.GetSubtree(0);");
int i = 0;
sb.AppendFormat("if(subtree.Symbol.Name == \"{0}\") {{ ", lookahead.First()).AppendLine();
foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, i++)) {
sb.AppendLine(GenerateSourceForAction(e));
}
foreach (var l in lookahead.Skip(1)) {
sb.AppendFormat("}} else if(subtree.Symbol.Name == \"{0}\") {{ ", l).AppendLine();
foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, i++)) {
sb.AppendLine(GenerateSourceForAction(e));
}
}
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();
} else {
int eIdx = 0;
foreach (var e in g.GetSequenceWithSemanticActions(s.Ident, 0)) {
if (e is CallSymbolNode) {
sb.AppendFormat("subtree = tree.GetSubtree({0});", eIdx++);
}
sb.AppendLine(GenerateSourceForAction(e));
}
}
sb.AppendLine("}");
return sb.ToString();
}
private string GenerateSourceForAction(RuleExprNode e) {
var action = e as RuleActionNode;
var call = e as CallSymbolNode;
if (action != null) {
return action.SrcCode + ";";
} else if (call != null) {
if (!call.ActualParameter.Any())
return string.Format("{0}(subtree);", call.Ident);
else
return string.Format("{0}(subtree, {1});", call.Ident, call.ActualParameter);
} else {
throw new ArgumentException();
}
}
private void GenerateGrammar(GPDefNode definition) {
IEnumerable ntSymbols = definition.NonTerminals;
IEnumerable tSymbols = definition.Terminals;
List ruleNodes = definition.Rules;
var g = new Grammar(ntSymbols, tSymbols, ruleNodes);
Console.WriteLine(g);
var grammarClassCode =
grammarClassTemplate
.Replace("?IDENT?", definition.Name)
.Replace("?CREATESYMBOLS?", GenerateGrammarSymbolDefinitionSource(g))
.Replace("?ROOTSYMBOL?", "_" + g.RootSymbol)
.Replace("?SETSUBTREECOUNTS?", GenerateGrammarSubtreeCountDefinitionSource(g))
.Replace("?SETALLOWEDSUBTREECOUNTS?", GenerateGrammarAllowedSubtreeDefinitionSource(g));
problemSourceCode.AppendLine(grammarClassCode).AppendLine();
}
private string GenerateGrammarSymbolDefinitionSource(Grammar g) {
StringBuilder sb = new StringBuilder();
foreach (var sy in g.Symbols) {
sb.AppendFormat("var _{0} = new {0}(problem); AddSymbol(_{0});", sy).AppendLine();
}
return sb.ToString();
}
private string GenerateGrammarSubtreeCountDefinitionSource(Grammar g) {
StringBuilder sb = new StringBuilder();
foreach (var sy in g.Symbols) {
var alt = g.GetAlternatives(sy);
if (alt.Count() > 0) {
var minSeqLength = alt.Min(seq => seq.Count);
var maxSeqLength = alt.Max(seq => seq.Count);
sb.AppendFormat("SetSubtreeCount(_{0}, {1}, {2});", sy, maxSeqLength, minSeqLength).AppendLine();
} else {
sb.AppendFormat("SetSubtreeCount(_{0}, {1}, {2});", sy, 0, 0).AppendLine();
}
}
return sb.ToString();
}
private string GenerateGrammarAllowedSubtreeDefinitionSource(Grammar g) {
StringBuilder sb = new StringBuilder();
foreach (var sy in g.Symbols) {
foreach (var seq in g.GetAlternatives(sy)) {
for (int argIdx = 0; argIdx < seq.Count; argIdx++) {
var childSy = seq[argIdx];
sb.AppendFormat("AddAllowedChildSymbol(_{0}, _{1}, {2});", sy, childSy, argIdx).AppendLine();
}
}
}
return sb.ToString();
}
private void GenerateTreeNodes(IEnumerable symbols) {
foreach (var s in symbols.OfType()) {
var classCode = treeNodeClassTemplate
.Replace("?IDENT?", s.Ident)
.Replace("?RESETFIELDSCODE?", GenerateNodeInitSourceCode(s))
.Replace("?SHAKEFIELDSCODE?", GenerateNodeUpdateSourceCode(s))
;
StringBuilder fieldSource = new StringBuilder();
StringBuilder cloningSource = new StringBuilder();
foreach (var par in s.FieldDefinitions) {
fieldSource.AppendLine("[Storable]");
fieldSource.Append("internal ").Append(par.Type).Append(" ").Append(par.Identifier).AppendLine(";");
cloningSource.Append("this.").Append(par.Identifier)
.Append("=").Append("(").Append(par.Type).Append(")")
.Append("original.").Append(par.Identifier).AppendLine(";");
}
classCode = classCode.Replace("?FIELDS?", fieldSource.ToString());
classCode = classCode.Replace("?CLONECODE?", cloningSource.ToString());
problemSourceCode
.AppendLine(classCode)
.AppendLine();
}
}
private string GenerateNodeInitSourceCode(TerminalNode s) {
var sb = new StringBuilder();
sb.AppendLine("var problem = Symbol.problem;");
foreach (var f in s.FieldDefinitions) {
var cType = GetConstraintTypeFor(f.Identifier, s.Constraints);
if (cType == ConstraintNodeType.Range) {
sb.AppendFormat("var max_{1} = problem.GetMax{0}_{1}();", s.Ident, f.Identifier).AppendLine();
sb.AppendFormat("var min_{1} = problem.GetMin{0}_{1}();", s.Ident, f.Identifier).AppendLine();
sb.AppendFormat("{0} = min_{0} + random.NextDouble() * (max_{0} - min_{0});", f.Identifier).AppendLine();
} else if (cType == ConstraintNodeType.Set) {
sb.AppendFormat("var set_{1} = problem.GetAllowed{0}_{1}().ToList();", s.Ident, f.Identifier).AppendLine();
sb.AppendFormat("{0} = set_{0}[random.Next(set_{0}.Count())];", f.Identifier).AppendLine();
}
}
return sb.ToString();
}
private string GenerateNodeUpdateSourceCode(TerminalNode s) {
var sb = new StringBuilder();
sb.AppendLine("var problem = Symbol.problem;");
foreach (var f in s.FieldDefinitions) {
var cType = GetConstraintTypeFor(f.Identifier, s.Constraints);
if (cType == ConstraintNodeType.Range) {
sb.AppendFormat("var max_{1} = problem.GetMax{0}_{1}();", s.Ident, f.Identifier).AppendLine();
sb.AppendFormat("var min_{1} = problem.GetMin{0}_{1}();", s.Ident, f.Identifier).AppendLine();
sb.AppendFormat("{0} = min_{0} + random.NextDouble() * (max_{0} - min_{0});", f.Identifier).AppendLine();
} else if (cType == ConstraintNodeType.Set) {
sb.AppendFormat("var set_{1} = problem.GetAllowed{0}_{1}().ToList();", s.Ident, f.Identifier).AppendLine();
sb.AppendFormat("{0} = set_{0}[random.Next(set_{0}.Count())];", f.Identifier).AppendLine();
}
}
return sb.ToString();
}
private ConstraintNodeType GetConstraintTypeFor(string id, IEnumerable contraints) {
return contraints.Single(c => c.Ident == id).Type;
}
private void GenerateSymbols(List symbols) {
foreach (var s in symbols.OfType()) {
problemSourceCode
.AppendLine(symbolClassTemplate.Replace("?IDENT?", s.Ident))
.AppendLine();
}
foreach (var s in symbols.OfType()) {
problemSourceCode
.AppendLine(terminalSymbolClassTemplate.Replace("?IDENT?", s.Ident))
.AppendLine();
}
}
}
}