#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(); } } } }