Changeset 10080 for branches/HeuristicLab.Problems.GPDL/CodeGenerator
- Timestamp:
- 10/22/13 20:39:15 (11 years ago)
- Location:
- branches/HeuristicLab.Problems.GPDL/CodeGenerator
- Files:
-
- 2 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/HeuristicLab.Problems.GPDL/CodeGenerator/BruteForceCodeGen.cs
r10074 r10080 5 5 using System.Linq; 6 6 using System.Text; 7 using System.Threading.Tasks;8 7 using HeuristicLab.Grammars; 9 8 using Attribute = HeuristicLab.Grammars.Attribute; … … 254 253 255 254 256 // find formal parameters of root node255 // get formal parameters of start symbol 257 256 var attr = grammar.StartSymbol.Attributes; 258 257 -
branches/HeuristicLab.Problems.GPDL/CodeGenerator/CodeGenerator.csproj
r10067 r10080 38 38 <Compile Include="BruteForceCodeGen.cs" /> 39 39 <Compile Include="Properties\AssemblyInfo.cs" /> 40 <Compile Include="RandomSearchCodeGen.cs" /> 40 41 </ItemGroup> 41 42 <ItemGroup> -
branches/HeuristicLab.Problems.GPDL/CodeGenerator/RandomSearchCodeGen.cs
r10078 r10080 5 5 using System.Linq; 6 6 using System.Text; 7 using System.Threading.Tasks;8 7 using HeuristicLab.Grammars; 9 8 using Attribute = HeuristicLab.Grammars.Attribute; 10 9 11 10 namespace CodeGenerator { 12 public class BruteForceCodeGen {11 public class RandomSearchCodeGen { 13 12 14 13 private string usings = @" … … 39 38 } 40 39 41 private class SearchTree { 42 private SearchTree[] subTrees; 43 public bool Done { get; private set; } 44 private int nextAlternative; 45 46 public SearchTree() { 47 Done = false; 48 } 49 50 public SearchTree GetSubtree(int i) { 51 // if (subTrees[i] == null) subTrees[i] = new SearchTree(); 52 return subTrees[i]; 53 } 54 55 public int GetNextAlternative() { 56 System.Diagnostics.Debug.Assert(IsAlternativeNode); 57 return nextAlternative; 58 } 59 60 public bool IsUninitialized { 61 get { return subTrees == null; } 62 } 63 64 public void SetNumberOfSubtrees(int n) { 65 this.subTrees = new SearchTree[n]; 66 for(int i=0;i<n;i++) this.subTrees[i] = new SearchTree(); 67 nextAlternative = 0; 68 } 69 70 public void UpdatePath() { 71 System.Diagnostics.Debug.Assert(!Done); 72 if (IsUninitialized) { return; } 73 Count++; 74 if (subTrees.Length == 0) { 75 Done = true; 76 } 77 if (IsAlternativeNode) { 78 // update only the active alternative and calculate a new alternative 79 subTrees[nextAlternative].UpdatePath(); 80 81 do { 82 nextAlternative = (nextAlternative + 1) % subTrees.Length; 83 } while (subTrees[nextAlternative] != null && subTrees[nextAlternative].Done); 84 85 // from the nodes which are not done take the first with minimum count 86 //nextAlternative = (from i in Enumerable.Range(0, subTrees.Length) 87 // where subTrees[i] == null || !subTrees[i].Done 88 // orderby subTrees[i]==null?0:subTrees[i].Count ascending 89 // select i).FirstOrDefault(); // possibly there are no children left that can be tried 90 } else { 91 // for sequenceNodes update all sub-trees 92 foreach (var t in subTrees) t.UpdatePath(); 93 } 94 // set node to done if all nodes are non-null and done 95 this.Done = true; 96 foreach(var t in subTrees) { 97 if(t == null || !t.Done) 98 { this.Done = false; break; } 99 } 100 } 101 102 public bool IsAlternativeNode { get; set; } 103 public bool IsSequenceNode { get; set; } 104 public int Count { get; private set; } 105 } 106 107 private SearchTree tree; 40 41 private Random seedRandom; 42 private int currentSeed; 108 43 private void Start() { 109 // start with empty tree 110 tree = new SearchTree(); 44 seedRandom = new Random(); 111 45 var bestF = ?MAXIMIZATION? ? double.NegativeInfinity : double.PositiveInfinity; 112 46 int n = 0; 113 47 var sw = new System.Diagnostics.Stopwatch(); 114 48 sw.Start(); 115 while (!tree.Done) { 116 49 while (true) { 50 51 // must make sure that calling the start-symbol multiple times in the fitness function always leads to the same path through the grammar 52 // so we use a PRNG for generating seeds for a separate PRNG that is reset each time the start symbol is called 53 currentSeed = seedRandom.Next(); 117 54 var f = Calculate(); 118 // do one more run through the tree to update the path119 tree.UpdatePath();120 55 121 56 n++; … … 243 178 sb.AppendFormat("public {0} GetMin{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMinExpression).AppendLine(); 244 179 } else if (c.Type == ConstraintNodeType.Set) { 245 sb.AppendFormat("public {0}[] GetAllowed{1}_{2}() {{ return {3}.ToArray(); }}", fieldType, t.Ident, c.Ident, c.SetExpression).AppendLine(); 246 } 247 sb.AppendFormat("public {0} Get{1}_{2}Element(int i) {{ return GetAllowed{1}_{2}()[i]; }}", fieldType, t.Ident, c.Ident); 180 sb.AppendFormat("public IEnumerable<{0}> GetAllowed{1}_{2}() {{ return {3} }}", fieldType, t.Ident, c.Ident, c.SetExpression).AppendLine(); 181 } 248 182 } 249 183 return sb.ToString(); … … 252 186 private string GenerateInterpreterSource(AttributedGrammar grammar) { 253 187 var sb = new StringBuilder(); 254 255 256 // find formal parameters of root node257 var attr = grammar.StartSymbol.Attributes;258 259 var formalParameter = grammar.StartSymbol.GetAttributeString();260 // actual parameter are the same as formalparameter only without type identifier261 string actualParameter;262 if (attr.Any())263 actualParameter = attr.Skip(1).Aggregate(attr.First().AttributeType + " " + attr.First().Name, (str, a) => str + ", " + a.AttributeType + " " + a.Name);264 else265 actualParameter = string.Empty;266 267 // generate entry method for evaluation. This is called from the min/max function268 // e.g.: ProgramRoot(ref int a0) { ProgramRoot(rootNode , ref a0); }269 sb.AppendFormat("void {0}({1}) {{", grammar.StartSymbol.Name, formalParameter).AppendLine();270 sb.AppendFormat("{0}(tree, {1});", grammar.StartSymbol.Name, actualParameter).AppendLine();271 sb.AppendLine("}");272 188 273 189 // generate methods for all nonterminals and terminals using the grammar instance … … 285 201 // if the terminal symbol has attributes then we must create values for these attributes 286 202 if (!s.Attributes.Any()) 287 sb.AppendFormat("private void {0}( SearchTree tree) {{", s.Name);203 sb.AppendFormat("private void {0}(Random random) {{", s.Name); 288 204 else 289 sb.AppendFormat("private void {0}(SearchTree tree, {1}) {{", s.Name, s.GetAttributeString()); 290 291 sb.AppendFormat("if (tree.IsUninitialized) {{ tree.SetNumberOfSubtrees({0}); tree.IsSequenceNode = true; }}", s.Attributes.Count()); 205 sb.AppendFormat("private void {0}(Random random, {1}) {{", s.Name, s.GetAttributeString()); 206 292 207 // each field must match a formal parameter, assign a value for each parameter 293 int i = 0;294 208 foreach (var element in s.Attributes) { 295 // read next symbol 296 sb.AppendLine("throw new NotImplementedException(); // this is not yet supported "); 297 sb.AppendFormat("{0} = Get{1}_{0}Element(tree.GetSubTree({2}).GetAlternative())", element.Name, s.Name, i++).AppendLine(";"); 209 // only works for "IN SET"-Constraints 210 sb.AppendFormat("{{ var tmp = GetAllowed{1}_{0}().ToArray(); {0} = tmp[random.Next(tmp.Length)]; }} ", element.Name, s.Name); 298 211 } 299 212 sb.AppendLine("}"); … … 303 216 private string GenerateInterpreterMethod(AttributedGrammar g, ISymbol s) { 304 217 var sb = new StringBuilder(); 218 // if this is the start symbol we additionally have to create the method which can be called from the fitness function 219 220 if (g.StartSymbol.Equals(s)) { 221 if (!s.Attributes.Any()) 222 sb.AppendFormat("private void {0}() {{", s.Name); 223 else 224 sb.AppendFormat("private void {0}({1}) {{", s.Name, s.GetAttributeString()); 225 226 // get formal parameters of start symbol 227 var attr = g.StartSymbol.Attributes; 228 229 // actual parameter are the same as formalparameter only without type identifier 230 string actualParameter; 231 if (attr.Any()) 232 actualParameter = attr.Skip(1).Aggregate(attr.First().AttributeType + " " + attr.First().Name, (str, a) => str + ", " + a.AttributeType + " " + a.Name); 233 else 234 actualParameter = string.Empty; 235 236 sb.AppendFormat("{0}(new Random(currentSeed), {1});", g.StartSymbol.Name, actualParameter).AppendLine(); 237 sb.AppendLine("}"); 238 } 239 305 240 if (!s.Attributes.Any()) 306 sb.AppendFormat("private void {0}( SearchTree tree) {{", s.Name);241 sb.AppendFormat("private void {0}(Random random) {{", s.Name); 307 242 else 308 sb.AppendFormat("private void {0}( SearchTree tree, {1}) {{", s.Name, s.GetAttributeString());243 sb.AppendFormat("private void {0}(Random random, {1}) {{", s.Name, s.GetAttributeString()); 309 244 310 245 // generate local definitions … … 312 247 313 248 314 315 // make sure we first descent into terminal alternatives -> we just order by number of non-terminals in the alternative 316 var altsWithSemActions = g.GetAlternativesWithSemanticActions(s).OrderBy(alt => alt.Count(symb => g.IsNonTerminal(symb))).ToArray(); 249 var altsWithSemActions = g.GetAlternativesWithSemanticActions(s).ToArray(); 250 var terminalAlts = altsWithSemActions.Where(alt => alt.Count(g.IsNonTerminal) == 0); 251 var nonTerminalAlts = altsWithSemActions.Where(alt => alt.Count(g.IsNonTerminal) > 0); 252 bool hasTerminalAlts = terminalAlts.Count() > 0; 253 bool hasNonTerminalAlts = nonTerminalAlts.Count() > 0; 317 254 318 255 if (altsWithSemActions.Length > 1) { 319 sb.AppendFormat(" if (tree.IsUninitialized) {{ tree.SetNumberOfSubtrees({0}); tree.IsAlternativeNode = true; }}", altsWithSemActions.Length); 320 321 int i = 0; 322 sb.AppendLine("switch(tree.GetNextAlternative()) {"); 323 // generate a case for each alternative 324 foreach (var alt in altsWithSemActions) { 325 sb.AppendFormat("case {0}: {{ ", i).AppendLine(); 326 sb.AppendLine("SearchTree subtree = null; "); 327 328 // this only works for alternatives with a single non-terminal symbol (ignoring semantic symbols) so far! 329 // handling multiple non-terminals here would require a change in the structure of the search tree 330 // another way to handle this is through grammar transformation (the examplary grammars all have the correct from) 331 Debug.Assert(alt.Count(symb => !(symb is SemanticSymbol)) == 1); 332 foreach (var altSymb in alt) { 333 if (!(altSymb is SemanticSymbol)) sb.AppendFormat("subtree = tree.GetSubtree({0}); ", i); 334 sb.AppendLine(GenerateSourceForAction(altSymb)); 335 } 336 i++; 337 sb.AppendLine("break;").AppendLine("}"); 338 } 339 sb.AppendLine("default: throw new System.InvalidOperationException();").AppendLine("}"); 256 // here we need to bias the selection of alternatives (non-terminal vs terminal alternatives) to make sure that 257 // terminals are selected with a certain probability to make sure that: 258 // 1) we don't create the same small trees all the time (terminals have high probability to be selected) 259 // 2) we don't create very big trees by recursing to deep (leads to stack-overflow) (terminals have a low probability to be selected) 260 // so we first decide if we want to generate a terminal or non-terminal (50%, 50%) and then choose a symbol in the class randomly 261 // the probability of choosing terminals should depend on the depth of the tree (small likelihood to choose terminals for small depths, large likelihood for large depths) 262 if (hasTerminalAlts && hasNonTerminalAlts) { 263 sb.AppendLine("if(random.NextDouble() < 0.5) {"); 264 // terminals 265 sb.AppendLine("// terminals "); 266 GenerateSwitchStatement(sb, terminalAlts); 267 sb.AppendLine("} else {"); 268 // non-terminals 269 sb.AppendLine("// non-terminals "); 270 GenerateSwitchStatement(sb, nonTerminalAlts); 271 sb.AppendLine("}"); 272 } else if (hasTerminalAlts) { 273 sb.AppendLine("// terminals "); 274 GenerateSwitchStatement(sb, terminalAlts); 275 } else if (hasNonTerminalAlts) { 276 sb.AppendLine("// non-terminals "); 277 GenerateSwitchStatement(sb, nonTerminalAlts); 278 } 340 279 } else { 341 sb.AppendFormat(" if (tree.IsUninitialized) {{ tree.SetNumberOfSubtrees({0}); tree.IsSequenceNode = true; }}", altsWithSemActions.Single().Count(symb => !(symb is SemanticSymbol)));342 int j = 0;343 sb.AppendLine("SearchTree subtree = null; ");344 280 foreach (var altSymb in altsWithSemActions.Single()) { 345 if (!(altSymb is SemanticSymbol)) sb.AppendFormat("subtree = tree.GetSubtree({0}); ", j++);346 281 sb.AppendLine(GenerateSourceForAction(altSymb)); 347 282 } … … 349 284 sb.AppendLine("}"); 350 285 return sb.ToString(); 286 } 287 288 private void GenerateSwitchStatement(StringBuilder sb, IEnumerable<Sequence> alts) { 289 sb.AppendFormat("switch(random.Next({0})) {{", alts.Count()); 290 // generate a case for each alternative 291 int i = 0; 292 foreach (var alt in alts) { 293 sb.AppendFormat("case {0}: {{ ", i).AppendLine(); 294 295 // this only works for alternatives with a single non-terminal symbol (ignoring semantic symbols) so far! 296 // a way to handle this is through grammar transformation (the examplary grammars all have the correct from) 297 Debug.Assert(alt.Count(symb => !(symb is SemanticSymbol)) == 1); 298 foreach (var altSymb in alt) { 299 sb.AppendLine(GenerateSourceForAction(altSymb)); 300 } 301 i++; 302 sb.AppendLine("break;").AppendLine("}"); 303 } 304 sb.AppendLine("default: throw new System.InvalidOperationException();").AppendLine("}"); 305 351 306 } 352 307 … … 358 313 } else { 359 314 if (!s.Attributes.Any()) 360 return string.Format("{0}( subtree);", s.Name);315 return string.Format("{0}(random);", s.Name); 361 316 else 362 return string.Format("{0}( subtree, {1});", s.Name, s.GetAttributeString());317 return string.Format("{0}(random, {1});", s.Name, s.GetAttributeString()); 363 318 } 364 319 }
Note: See TracChangeset
for help on using the changeset viewer.