Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.3/Creators/ProbabilisticTreeCreator.cs @ 3369

Last change on this file since 3369 was 3369, checked in by gkronber, 14 years ago

Changed way the grammar is stored in tree nodes to make it more efficient and fixed bugs in symbolic expression tree operators. #290 (Implement ADFs)

File size: 14.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using HeuristicLab.Core;
23using HeuristicLab.Data;
24using HeuristicLab.Random;
25using System;
26using System.Linq;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28using System.Collections.Generic;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.GeneralSymbols;
30using System.Text;
31using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ArchitectureAlteringOperators;
32
33namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
34  [StorableClass]
35  [Item("ProbabilisticTreeCreator", "An operator that creates new symbolic expression trees with uniformly distributed size")]
36  public class ProbabilisticTreeCreator : SymbolicExpressionTreeCreator {
37    private const int MAX_TRIES = 100;
38
39    public ProbabilisticTreeCreator()
40      : base() {
41    }
42
43    protected override SymbolicExpressionTree Create(
44      IRandom random,
45      ISymbolicExpressionGrammar grammar,
46      IntValue maxTreeSize, IntValue maxTreeHeight,
47      IntValue maxFunctionDefinitions, IntValue maxFunctionArguments) {
48      return Create(random, grammar, maxTreeSize.Value, maxTreeHeight.Value, maxFunctionDefinitions.Value, maxFunctionArguments.Value);
49    }
50
51    public static SymbolicExpressionTree Create(IRandom random, ISymbolicExpressionGrammar grammar,
52      int maxTreeSize, int maxTreeHeight,
53      int maxFunctionDefinitions, int maxFunctionArguments
54      ) {
55      SymbolicExpressionTree tree = new SymbolicExpressionTree();
56      var rootNode = grammar.StartSymbol.CreateTreeNode();
57      rootNode.Grammar = grammar;
58      tree.Root = PTC2(random, rootNode, maxTreeSize, maxTreeHeight, maxFunctionDefinitions, maxFunctionArguments);
59      return tree;
60    }
61
62    private class TreeExtensionPoint {
63      public SymbolicExpressionTreeNode Parent { get; set; }
64      public int ChildIndex { get; set; }
65      public int ExtensionPointDepth { get; set; }
66    }
67
68    public static SymbolicExpressionTreeNode PTC2(IRandom random, SymbolicExpressionTreeNode seedNode,
69      int maxTreeSize, int maxDepth, int maxFunctionDefinitions, int maxFunctionArguments) {
70      // tree size is limited by the grammar and by the explicit size constraints
71      int allowedMinSize = seedNode.Grammar.GetMinExpressionLength(seedNode.Symbol);
72      int allowedMaxSize = Math.Min(maxTreeSize, seedNode.Grammar.GetMaxExpressionLength(seedNode.Symbol));
73      int tries = 0;
74      while (tries++ < MAX_TRIES) {
75        // select a target tree size uniformly in the possible range (as determined by explicit limits and limits of the grammar)
76        int treeSize = random.Next(allowedMinSize, allowedMaxSize + 1);
77        if (treeSize <= 1 || maxDepth <= 1) return seedNode;
78
79        bool success = CreateFullTreeFromSeed(random, seedNode, seedNode.Grammar, treeSize, maxDepth, maxFunctionDefinitions, maxFunctionArguments);
80
81        // if successfull => check constraints and return the tree if everything looks ok       
82        if (success && seedNode.GetSize() <= maxTreeSize && seedNode.GetHeight() <= maxDepth) {
83          return seedNode;
84        } else {
85          // clean seedNode
86          while (seedNode.SubTrees.Count > 0) seedNode.RemoveSubTree(0);
87        }
88        // try a different size MAX_TRIES times
89      }
90      throw new ArgumentException("Couldn't create a valid tree with the specified constraints.");
91    }
92
93    private static bool CreateFullTreeFromSeed(IRandom random, SymbolicExpressionTreeNode root, ISymbolicExpressionGrammar globalGrammar,
94      int size, int maxDepth, int maxFunctionDefinitions, int maxFunctionArguments) {
95      try {
96        TryCreateFullTreeFromSeed(random, root, globalGrammar, size, maxDepth, maxFunctionDefinitions, maxFunctionArguments);
97        return true;
98      }
99      catch (ArgumentException) { return false; }
100    }
101
102    private static void TryCreateFullTreeFromSeed(IRandom random, SymbolicExpressionTreeNode root, ISymbolicExpressionGrammar globalGrammar,
103      int size, int maxDepth, int maxFunctionDefinitions, int maxFunctionArguments) {
104      List<TreeExtensionPoint> extensionPoints = new List<TreeExtensionPoint>();
105      int currentSize = 1;
106      int totalListMinSize = globalGrammar.GetMinExpressionLength(root.Symbol) - 1;
107      int actualArity = SampleArity(random, root, size);
108      for (int i = 0; i < actualArity; i++) {
109        // insert a dummy sub-tree and add the pending extension to the list
110        var dummy = new SymbolicExpressionTreeNode();
111        root.AddSubTree(dummy);
112        // dummy.Grammar = (ISymbolicExpressionGrammar)dummy.Grammar.Clone();
113        extensionPoints.Add(new TreeExtensionPoint { Parent = root, ChildIndex = i, ExtensionPointDepth = 2 });
114      }
115      // while there are pending extension points and we have not reached the limit of adding new extension points
116      while (extensionPoints.Count > 0 && totalListMinSize + currentSize < size) {
117        int randomIndex = random.Next(extensionPoints.Count);
118        TreeExtensionPoint nextExtension = extensionPoints[randomIndex];
119        extensionPoints.RemoveAt(randomIndex);
120        SymbolicExpressionTreeNode parent = nextExtension.Parent;
121        int argumentIndex = nextExtension.ChildIndex;
122        int extensionDepth = nextExtension.ExtensionPointDepth;
123        if (extensionDepth + parent.Grammar.GetMinExpressionDepth(parent.Symbol) >= maxDepth) {
124          ReplaceWithMinimalTree(random, root, parent, argumentIndex, maxFunctionDefinitions, maxFunctionArguments);
125        } else {
126          var allowedSymbols = from s in parent.Grammar.Symbols
127                               where parent.Grammar.IsAllowedChild(parent.Symbol, s, argumentIndex)
128                               where parent.Grammar.GetMinExpressionDepth(s) + extensionDepth - 1 < maxDepth
129                               where parent.Grammar.GetMaxExpressionLength(s) > size - totalListMinSize - currentSize
130                               select s;
131          Symbol selectedSymbol = SelectRandomSymbol(random, allowedSymbols);
132          SymbolicExpressionTreeNode newTree = selectedSymbol.CreateTreeNode();
133          parent.RemoveSubTree(argumentIndex);
134          parent.InsertSubTree(argumentIndex, newTree);
135
136          InitializeNewTreeNode(random, root, newTree, maxFunctionDefinitions, maxFunctionArguments);
137
138          currentSize++;
139          totalListMinSize--;
140
141          actualArity = SampleArity(random, newTree, size - currentSize);
142          for (int i = 0; i < actualArity; i++) {
143            // insert a dummy sub-tree and add the pending extension to the list
144            var dummy = new SymbolicExpressionTreeNode();
145            newTree.AddSubTree(dummy);
146            //if (IsTopLevelBranch(root, dummy))
147            //  dummy.Grammar = (ISymbolicExpressionGrammar)dummy.Grammar.Clone();
148            extensionPoints.Add(new TreeExtensionPoint { Parent = newTree, ChildIndex = i, ExtensionPointDepth = extensionDepth + 1 });
149          }
150          totalListMinSize += newTree.Grammar.GetMinExpressionLength(newTree.Symbol);
151        }
152      }
153      // fill all pending extension points
154      while (extensionPoints.Count > 0) {
155        int randomIndex = random.Next(extensionPoints.Count);
156        TreeExtensionPoint nextExtension = extensionPoints[randomIndex];
157        extensionPoints.RemoveAt(randomIndex);
158        SymbolicExpressionTreeNode parent = nextExtension.Parent;
159        int a = nextExtension.ChildIndex;
160        int d = nextExtension.ExtensionPointDepth;
161        ReplaceWithMinimalTree(random, root, parent, a, maxFunctionDefinitions, maxFunctionArguments);
162      }
163    }
164
165    private static void ReplaceWithMinimalTree(IRandom random, SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode parent, int argumentIndex, int maxFunctionDefinitions, int maxFunctionArguments) {
166      // determine possible symbols that will lead to the smallest possible tree
167      var possibleSymbols = (from s in parent.GetAllowedSymbols(argumentIndex)
168                             group s by parent.Grammar.GetMinExpressionLength(s) into g
169                             orderby g.Key
170                             select g).First();
171      var selectedSymbol = SelectRandomSymbol(random, possibleSymbols);
172      var tree = selectedSymbol.CreateTreeNode();
173      parent.RemoveSubTree(argumentIndex);
174      parent.InsertSubTree(argumentIndex, tree);
175      InitializeNewTreeNode(random, root, tree, maxFunctionDefinitions, maxFunctionArguments);
176      for (int i = 0; i < tree.GetMinSubtreeCount(); i++) {
177        // insert a dummy sub-tree and add the pending extension to the list
178        var dummy = new SymbolicExpressionTreeNode();
179        tree.AddSubTree(dummy);
180        // dummy.Grammar = (ISymbolicExpressionGrammar)dummy.Grammar.Clone();
181        // replace the just inserted dummy by recursive application
182        ReplaceWithMinimalTree(random, root, tree, i, maxFunctionDefinitions, maxFunctionArguments);
183      }
184    }
185
186    private static void InitializeNewTreeNode(IRandom random, SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode newTree, int maxFunctionDefinitions, int maxFunctionArguments) {
187      // NB it is assumed that defuns are only allowed as children of root and nowhere else
188      // also assumes that newTree is already attached to root somewhere
189      if (IsTopLevelBranch(root, newTree)) {
190        newTree.Grammar = (ISymbolicExpressionGrammar)root.Grammar.Clone();
191
192        // allow invokes of existing ADFs with higher index
193        int argIndex = root.SubTrees.IndexOf(newTree);
194        for (int i = argIndex + 1; i < root.SubTrees.Count; i++) {
195          var otherDefunNode = root.SubTrees[i] as DefunTreeNode;
196          if (otherDefunNode != null) {
197            GrammarModifier.AddDynamicSymbol(newTree.Grammar, newTree.Symbol, otherDefunNode.FunctionName, otherDefunNode.NumberOfArguments);
198          }
199        }
200      }
201      if (newTree.Symbol is Defun) {
202        var defunTree = newTree as DefunTreeNode;
203        string formatString = new StringBuilder().Append('0', (int)Math.Log10(maxFunctionDefinitions * 10 - 1)).ToString(); // >= 100 functions => ###
204        var allowedNames = from index in Enumerable.Range(0, maxFunctionDefinitions)
205                           select "ADF" + index.ToString(formatString);
206        var takenNames = (from node in root.IterateNodesPrefix().OfType<DefunTreeNode>()
207                          select node.FunctionName).Distinct();
208        var remainingNames = allowedNames.Except(takenNames).ToList();
209        string functionName = remainingNames[random.Next(remainingNames.Count)];
210        // set name and number of arguments of the ADF
211        int nArgs = random.Next(maxFunctionArguments);
212        defunTree.FunctionName = functionName;
213        defunTree.NumberOfArguments = nArgs;
214        if (nArgs > 0) {
215          GrammarModifier.AddDynamicArguments(defunTree.Grammar, defunTree.Symbol, Enumerable.Range(0, nArgs));
216        }
217        // in existing branches with smaller index allow invoke of current function
218        int argIndex = root.SubTrees.IndexOf(newTree);
219        for (int i = 0; i < argIndex; i++) {
220          // if not dummy node
221          if (root.SubTrees[i].Symbol != null) {
222            var existingBranch = root.SubTrees[i];
223            GrammarModifier.AddDynamicSymbol(existingBranch.Grammar, existingBranch.Symbol, functionName, nArgs);
224          }
225        }
226      }
227    }
228
229    private static bool IsTopLevelBranch(SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode branch) {
230      //return root.SubTrees.IndexOf(branch) > -1;
231      return branch is SymbolicExpressionTreeTopLevelNode;
232    }
233
234    private static Symbol SelectRandomSymbol(IRandom random, IEnumerable<Symbol> symbols) {
235      var symbolList = symbols.ToList();
236      var ticketsSum = symbolList.Select(x => x.InitialFrequency).Sum();
237      var r = random.NextDouble() * ticketsSum;
238      double aggregatedTickets = 0;
239      for (int i = 0; i < symbolList.Count; i++) {
240        aggregatedTickets += symbolList[i].InitialFrequency;
241        if (aggregatedTickets >= r) {
242          return symbolList[i];
243        }
244      }
245      // this should never happen
246      throw new ArgumentException();
247    }
248
249    private static int SampleArity(IRandom random, SymbolicExpressionTreeNode node, int targetSize) {
250      // select actualArity randomly with the constraint that the sub-trees in the minimal arity can become large enough
251      int minArity = node.GetMinSubtreeCount();
252      int maxArity = node.GetMaxSubtreeCount();
253      if (maxArity > targetSize) {
254        maxArity = targetSize;
255      }
256      // the min number of sub-trees has to be set to a value that is large enough so that the largest possible tree is at least tree size
257      // if 1..3 trees are possible and the largest possible first sub-tree is smaller larger than the target size then minArity should be at least 2
258      long aggregatedLongestExpressionLength = 0;
259      for (int i = 0; i < maxArity; i++) {
260        aggregatedLongestExpressionLength += (from s in node.GetAllowedSymbols(i)
261                                              select node.Grammar.GetMaxExpressionLength(s)).Max();
262        if (aggregatedLongestExpressionLength < targetSize) minArity = i;
263        else break;
264      }
265
266      // the max number of sub-trees has to be set to a value that is small enough so that the smallest possible tree is at most tree size
267      // if 1..3 trees are possible and the smallest possible first sub-tree is already larger than the target size then maxArity should be at most 0
268      long aggregatedShortestExpressionLength = 0;
269      for (int i = 0; i < maxArity; i++) {
270        aggregatedShortestExpressionLength += (from s in node.GetAllowedSymbols(i)
271                                               select node.Grammar.GetMinExpressionLength(s)).Min();
272        if (aggregatedShortestExpressionLength > targetSize) {
273          maxArity = i;
274          break;
275        }
276      }
277      if (minArity > maxArity) throw new ArgumentException();
278      return random.Next(minArity, maxArity + 1);
279    }
280  }
281}
Note: See TracBrowser for help on using the repository browser.