Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GPDL/CodeGenerator/BruteForceCodeGen.cs @ 10425

Last change on this file since 10425 was 10425, checked in by gkronber, 10 years ago

#2026 support for max depth in brute force solver

File size: 7.7 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Linq;
5using System.Text;
6using HeuristicLab.Grammars;
7
8namespace CodeGenerator {
9  public class BruteForceCodeGen {
10
11    private string solverTemplate = @"
12
13namespace ?PROBLEMNAME? {
14  public sealed class ?IDENT?Solver {
15    private static int maxDepth = 20;
16
17    private readonly ?IDENT?Problem problem;
18    private readonly Random random;
19
20    private IEnumerable<Tree> GenerateTrees(int parentState, int depth) {
21      if(depth<=1) {
22        if(Grammar.subtreeCount[parentState] == 0)
23          foreach(var terminal in CreateTerminalNodes(parentState, problem))
24            yield return terminal;
25      } else if(Grammar.subtreeCount[parentState] == 1) {
26        for(int altIdx = 0; altIdx < Grammar.transition[parentState].Length; altIdx++) {
27          var targetState = Grammar.transition[parentState][altIdx];
28          foreach(var subtree in GenerateTrees(targetState, depth - 1)) {
29            var solution = new Tree(altIdx, new Tree[1] {subtree});
30            yield return solution;
31          }
32        }
33      } else if(Grammar.subtreeCount[parentState] > 1) {
34        var nums = Enumerable.Range(1, depth - 1);
35        var depthCombinations = CartesianProduct(Enumerable.Repeat(nums, Grammar.subtreeCount[parentState]))
36           .Where(comb => comb.Max() == depth - 1);
37        foreach(var depthCombination in depthCombinations) {
38          var trees = new IEnumerable<Tree>[Grammar.subtreeCount[parentState]];
39          var depthCombinationEnumerator = depthCombination.GetEnumerator();
40          depthCombinationEnumerator.MoveNext();
41          for(int subtreeIdx = 0; subtreeIdx < Grammar.subtreeCount[parentState]; subtreeIdx++) {
42            trees[subtreeIdx] = GenerateTrees(Grammar.transition[parentState][subtreeIdx], depthCombinationEnumerator.Current);
43            depthCombinationEnumerator.MoveNext();
44          }
45          foreach(var e in CartesianProduct(trees)) {
46            yield return new Tree(-1, e.ToArray()); // altIdx is ignored
47          }
48        }
49      }
50    }
51
52    public IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sets) {
53      if(sets.Count() == 1) {
54        foreach(var e in sets.First()) {
55          yield return new T[] {e};
56        }
57      }
58      else {
59        var firstSet = sets.First();
60        foreach(var e in firstSet) {
61          foreach(var p in CartesianProduct(sets.Skip(1))) {
62            yield return new T[] {e}.Concat(p);
63          }
64        }
65      }
66    }
67
68    private static IEnumerable<Tree> CreateTerminalNodes(int state, ?IDENT?Problem problem) {
69      switch(state) {
70        ?CREATETERMINALNODECODE?
71        default: { throw new ArgumentException(""Unknown state index"" + state); }
72      }
73    }
74
75    public static void Main(string[] args) {
76      if(args.Length > 0) ParseArguments(args);
77      var problem = new ?IDENT?Problem();
78      var solver = new ?IDENT?Solver(problem);
79      solver.Start();
80    }
81    private static void ParseArguments(string[] args) {
82      var maxDepthRegex = new Regex(@""--maxDepth=(?<d>.+)"");
83
84      var helpRegex = new Regex(@""--help|/\?"");
85     
86      foreach(var arg in args) {
87        var maxDepthMatch = maxDepthRegex.Match(arg);
88        var helpMatch = helpRegex.Match(arg);
89        if(helpMatch.Success) {
90          PrintUsage(); Environment.Exit(0);
91        } else if(maxDepthMatch.Success) {
92           maxDepth = int.Parse(maxDepthMatch.Groups[""d""].Captures[0].Value, System.Globalization.CultureInfo.InvariantCulture);
93           if(maxDepth < 1 || maxDepth > 100) throw new ArgumentException(""max depth must lie in range [1 ... 100]"");
94        } else {
95           Console.WriteLine(""Unknown switch {0}"", arg); PrintUsage(); Environment.Exit(0);
96        }
97      }
98    }
99    private static void PrintUsage() {
100      Console.WriteLine(""Find a solution using brute force tree search."");
101      Console.WriteLine();
102      Console.WriteLine(""Parameters:"");
103      Console.WriteLine(""\t--maxDepth=<depth>\tSets the maximal depth of sampled trees [Default: 20]"");
104      Console.WriteLine(""\t--help\tPrints this help text."");
105    }
106
107
108    public ?IDENT?Solver(?IDENT?Problem problem) {
109      this.problem = problem;
110      this.random = new Random();
111    }
112
113    private void Start() {
114      var bestF = ?MAXIMIZATION? ? double.NegativeInfinity : double.PositiveInfinity;
115      int n = 0;
116      long sumDepth = 0;
117      long sumSize = 0;
118      var sumF = 0.0;
119      var sw = new System.Diagnostics.Stopwatch();
120      sw.Start();
121      for(int depth = 1; depth < maxDepth; depth ++) {
122        Console.WriteLine(""Depth {0}:"", depth);
123        foreach(var t in GenerateTrees(0, depth)) {
124          var f = problem.Evaluate(t);
125          // t.PrintTree(0); Console.WriteLine();
126          var size = t.GetSize();
127          sumSize += size;
128          sumDepth += depth;
129          n++;   
130          sumF += f;
131          if (problem.IsBetter(f, bestF)) {
132            bestF = f;
133            t.PrintTree(0); Console.WriteLine();
134            Console.WriteLine(""{0}\t{1}\t(size={2}, depth={3})"", n, bestF, size, depth);
135          }
136          if (n % 1000 == 0) {
137            sw.Stop();
138            Console.WriteLine(""{0}\tbest: {1:0.000}\t(avg: {2:0.000})\t(avg size: {3:0.0})\t(avg. depth: {4:0.0})\t({5:0.00} sols/ms)"",
139                              n, bestF, sumF/1000.0, sumSize/1000.0, sumDepth/1000.0, 1000.0 / sw.ElapsedMilliseconds);
140            sumSize = 0;
141            sumDepth = 0;
142            sumF = 0.0;
143            sw.Restart();
144          }
145        }
146        Console.WriteLine(""n={0}"",n);
147      }
148    }
149  }
150}";
151
152    public void Generate(IGrammar grammar, IEnumerable<TerminalNode> terminals, bool maximization, SourceBuilder problemSourceCode) {
153      var solverSourceCode = new SourceBuilder();
154      solverSourceCode.Append(solverTemplate)
155        .Replace("?MAXIMIZATION?", maximization.ToString().ToLowerInvariant())
156        .Replace("?CREATETERMINALNODECODE?", GenerateCreateTerminalCode(grammar, terminals))
157      ;
158
159      problemSourceCode.Append(solverSourceCode.ToString());
160    }
161
162    private string GenerateCreateTerminalCode(IGrammar grammar, IEnumerable<TerminalNode> terminals) {
163      Debug.Assert(grammar.Symbols.First().Equals(grammar.StartSymbol));
164      var sb = new SourceBuilder();
165      var allSymbols = grammar.Symbols.ToList();
166      foreach (var s in grammar.Symbols) {
167        if (grammar.IsTerminal(s)) {
168          sb.AppendFormat("case {0}: {{", allSymbols.IndexOf(s)).BeginBlock();
169          var terminal = terminals.Single(t => t.Ident == s.Name);
170          if (terminal.Constraints.Any(c => c.Type == ConstraintNodeType.Range)) {
171            throw new NotSupportedException("Sorry the brute force solver does not support RANGE constraints");
172          }
173          sb.AppendFormat("{0}Tree t = null;", terminal.Ident).AppendLine();
174          // create nested loop to produce all combinations of values (only set constraints)
175          foreach (var constr in terminal.Constraints) {
176            sb.AppendFormat("foreach(var {1} in problem.GetAllowed{0}_{1}()) {{;", terminal.Ident, constr.Ident).BeginBlock();
177          }
178          sb.AppendFormat("t = new {0}Tree();", terminal.Ident).AppendLine();
179
180          foreach (var constr in terminal.Constraints) {
181            sb.AppendFormat("t.{0} = {0};", constr.Ident);
182          }
183          sb.AppendLine("yield return t; ");
184
185          foreach (var _ in terminal.Constraints) {
186            sb.AppendLine("}").EndBlock();
187          }
188
189
190          sb.AppendLine(" break; }");
191        }
192      }
193      return sb.ToString();
194    }
195  }
196}
Note: See TracBrowser for help on using the repository browser.