Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3376 was 3376, checked in by swagner, 14 years ago

Moved interfaces and classes for deep cloning from HeuristicLab.Core to HeuristicLab.Common (#975).

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