Free cookie consent management tool by TermsFeed Policy Generator

Changeset 10080


Ignore:
Timestamp:
10/22/13 20:39:15 (10 years ago)
Author:
gkronber
Message:

#2026 implemented a code generator for random search solvers for GPDL problems

Location:
branches/HeuristicLab.Problems.GPDL
Files:
6 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.Problems.GPDL/CodeGenerator/BruteForceCodeGen.cs

    r10074 r10080  
    55using System.Linq;
    66using System.Text;
    7 using System.Threading.Tasks;
    87using HeuristicLab.Grammars;
    98using Attribute = HeuristicLab.Grammars.Attribute;
     
    254253
    255254
    256       // find formal parameters of root node
     255      // get formal parameters of start symbol
    257256      var attr = grammar.StartSymbol.Attributes;
    258257
  • branches/HeuristicLab.Problems.GPDL/CodeGenerator/CodeGenerator.csproj

    r10067 r10080  
    3838    <Compile Include="BruteForceCodeGen.cs" />
    3939    <Compile Include="Properties\AssemblyInfo.cs" />
     40    <Compile Include="RandomSearchCodeGen.cs" />
    4041  </ItemGroup>
    4142  <ItemGroup>
  • branches/HeuristicLab.Problems.GPDL/CodeGenerator/RandomSearchCodeGen.cs

    r10078 r10080  
    55using System.Linq;
    66using System.Text;
    7 using System.Threading.Tasks;
    87using HeuristicLab.Grammars;
    98using Attribute = HeuristicLab.Grammars.Attribute;
    109
    1110namespace CodeGenerator {
    12   public class BruteForceCodeGen {
     11  public class RandomSearchCodeGen {
    1312
    1413    private string usings = @"
     
    3938    }
    4039
    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;
    10843    private void Start() {
    109       // start with empty tree
    110       tree = new SearchTree();
     44      seedRandom = new Random();
    11145      var bestF = ?MAXIMIZATION? ? double.NegativeInfinity : double.PositiveInfinity;
    11246      int n = 0;
    11347      var sw = new System.Diagnostics.Stopwatch();
    11448      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();
    11754        var f = Calculate();
    118         // do one more run through the tree to update the path
    119         tree.UpdatePath();
    12055
    12156        n++;
     
    243178          sb.AppendFormat("public {0} GetMin{1}_{2}() {{ return {3}; }}", fieldType, t.Ident, c.Ident, c.RangeMinExpression).AppendLine();
    244179        } 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        }
    248182      }
    249183      return sb.ToString();
     
    252186    private string GenerateInterpreterSource(AttributedGrammar grammar) {
    253187      var sb = new StringBuilder();
    254 
    255 
    256       // find formal parameters of root node
    257       var attr = grammar.StartSymbol.Attributes;
    258 
    259       var formalParameter = grammar.StartSymbol.GetAttributeString();
    260       // actual parameter are the same as formalparameter only without type identifier
    261       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       else
    265         actualParameter = string.Empty;
    266 
    267       // generate entry method for evaluation. This is called from the min/max function
    268       // 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("}");
    272188
    273189      // generate methods for all nonterminals and terminals using the grammar instance
     
    285201      // if the terminal symbol has attributes then we must create values for these attributes
    286202      if (!s.Attributes.Any())
    287         sb.AppendFormat("private void {0}(SearchTree tree) {{", s.Name);
     203        sb.AppendFormat("private void {0}(Random random) {{", s.Name);
    288204      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
    292207      // each field must match a formal parameter, assign a value for each parameter
    293       int i = 0;
    294208      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);
    298211      }
    299212      sb.AppendLine("}");
     
    303216    private string GenerateInterpreterMethod(AttributedGrammar g, ISymbol s) {
    304217      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
    305240      if (!s.Attributes.Any())
    306         sb.AppendFormat("private void {0}(SearchTree tree) {{", s.Name);
     241        sb.AppendFormat("private void {0}(Random random) {{", s.Name);
    307242      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());
    309244
    310245      // generate local definitions
     
    312247
    313248
    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;
    317254
    318255      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        }
    340279      } 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; ");
    344280        foreach (var altSymb in altsWithSemActions.Single()) {
    345           if (!(altSymb is SemanticSymbol)) sb.AppendFormat("subtree = tree.GetSubtree({0}); ", j++);
    346281          sb.AppendLine(GenerateSourceForAction(altSymb));
    347282        }
     
    349284      sb.AppendLine("}");
    350285      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
    351306    }
    352307
     
    358313      } else {
    359314        if (!s.Attributes.Any())
    360           return string.Format("{0}(subtree);", s.Name);
     315          return string.Format("{0}(random);", s.Name);
    361316        else
    362           return string.Format("{0}(subtree, {1});", s.Name, s.GetAttributeString());
     317          return string.Format("{0}(random, {1});", s.Name, s.GetAttributeString());
    363318      }
    364319    }
  • branches/HeuristicLab.Problems.GPDL/Examples/Artificial Ant.txt

    r10074 r10080  
    66  public Point(int x, int y) {
    77    this.x = x;
    8   this.y = y;
     8    this.y = y;
    99  }
    1010};
     
    9595    if(p.x < 0 || p.y < 0) return false;
    9696    if(world.Length <= p.y) return false;
    97   if(world[p.y].Length <= p.x) return false;
     97    if(world[p.y].Length <= p.x) return false;
    9898    return world[p.y][p.x] == '#';
    9999  }
    100100  public void RemoveFoodAt(Point p) {
    101101    if(world.Length < p.y) return;
    102   if(world[p.y].Length < p.x) return;
     102    if(world[p.y].Length < p.x) return;
    103103    world[p.y][p.x] = ' ';
    104104  }
     
    116116 
    117117  public AntState() {
    118     Steps = 0; 
    119   FoodEaten = 0;
     118    Steps = 0;   
     119    FoodEaten = 0;
    120120  }
    121121 
     
    123123    Steps++;
    124124    switch(Direction) {
    125     case Direction.West: Direction = Direction.South; break;
    126     case Direction.South: Direction = Direction.East; break;
    127     case Direction.East: Direction = Direction.North; break;
    128     case Direction.North: Direction = Direction.West; break;
    129   }
     125      case Direction.West: Direction = Direction.South; break;
     126      case Direction.South: Direction = Direction.East; break;
     127      case Direction.East: Direction = Direction.North; break;
     128      case Direction.North: Direction = Direction.West; break;
     129    }
    130130  }
    131131  public void TurnRight() {
    132132    Steps++;
    133133    switch(Direction) {
    134     case Direction.West: Direction = Direction.North; break;
    135     case Direction.South: Direction = Direction.West; break;
    136     case Direction.East: Direction = Direction.South; break;
    137     case Direction.North: Direction = Direction.East; break;
    138   }
     134      case Direction.West: Direction = Direction.North; break;
     135      case Direction.South: Direction = Direction.West; break;
     136      case Direction.East: Direction = Direction.South; break;
     137      case Direction.North: Direction = Direction.East; break;
     138    }
    139139  }
    140140  public void MoveForward() {
    141141    Position = NextPosition;
    142   Steps++;
    143   if(World.FoodAt(Position)) {
    144       World.RemoveFoodAt(Position);
    145     FoodEaten++;
     142    Steps++;
     143    if(World.FoodAt(Position)) {
     144        World.RemoveFoodAt(Position);
     145        FoodEaten++;
    146146    }
    147147  }
    148148  public Point NextPosition {
    149149    get {
    150       int x, y;
     150        int x, y;
    151151        switch(Direction) {
    152         case Direction.West:
    153         x = (Position.x + World.Width - 1) % World.Width;
    154       y = Position.y;
    155       return new Point(x, y);
    156         case Direction.South:
    157           x = Position.x;
    158       y = (Position.y + World.Height + 1) % World.Height;
    159       return new Point(x, y);
    160         case Direction.East:
    161           x = (Position.x + World.Width + 1) % World.Width;
    162       y = Position.y;
    163       return new Point(x, y);
    164         case Direction.North:
    165           x = Position.x;
    166       y = (Position.y + World.Height - 1) % World.Height;
    167       return new Point(x, y);
    168       }
    169     return new Point(-1,-1);
     152          case Direction.West:
     153            x = (Position.x + World.Width - 1) % World.Width;
     154            y = Position.y;
     155            return new Point(x, y);
     156          case Direction.South:
     157              x = Position.x;
     158            y = (Position.y + World.Height + 1) % World.Height;
     159            return new Point(x, y);
     160          case Direction.East:
     161              x = (Position.x + World.Width + 1) % World.Width;
     162            y = Position.y;
     163            return new Point(x, y);
     164          case Direction.North:
     165              x = Position.x;
     166            y = (Position.y + World.Height - 1) % World.Height;
     167            return new Point(x, y);
     168        }
     169         return new Point(-1,-1);
    170170    }
    171171  } 
  • branches/HeuristicLab.Problems.GPDL/Examples/RoyalTree.txt

    r10079 r10080  
    11/* The Royal Tree benchmark problem for GP */
    22/* See paper: William F. Punch, How Effective are Multiple Populations in Genetic Programming */
    3 /*
    43/* for max. depth 7 (level: g) this is hard to solve. Full enumeration needs a lot of memory. */
     4
    55PROBLEM RoyalTree
    66CODE <<
  • branches/HeuristicLab.Problems.GPDL/GpdlCompiler/Program.cs

    r10062 r10080  
    3232      Parser parser = new Parser(scanner);
    3333      parser.Parse();
    34       var codeGen = new BruteForceCodeGen();
     34      var codeGen = new RandomSearchCodeGen();
    3535
    3636      codeGen.Generate(parser.AbstractSyntaxTree);
  • branches/HeuristicLab.Problems.GPDL/HeuristicLab.Problems.GPDL/3.4/Util.cs

    r10079 r10080  
    2929  private static string refOrOutGroup = @"(?:(?<refOrOut>(out|ref))\s+)"; // "ref " | "out "
    3030  private static string typeGroup = @"(?:(?<type>[^,]+)\s+)";
    31   private static string identGroup = @"(?<id>[^,]+)\s*";
     31  private static string identGroup = @"(?:(?<id>[^,]+)\s*)";
    3232  private static Regex formalParameterExpr = new Regex(@"\s*,?\s*" + refOrOutGroup + "?" + typeGroup + "?" + identGroup, RegexOptions.ECMAScript);
    3333  public static IEnumerable<TerminalNode.FieldDefinition> ExtractParameters(string formalParameterSrc) {
Note: See TracChangeset for help on using the changeset viewer.