Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.3/ArchitectureManipulators/ArgumentCreater.cs @ 4450

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

Fixed bugs in SubtreeCrossover, ArgumentCreater and ArgumentDuplicater and updated unit tests for symbolic expression tree operators. #1103

File size: 8.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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 System.Collections.Generic;
23using System.Linq;
24using HeuristicLab.Core;
25using HeuristicLab.Data;
26using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ArchitectureManipulators {
30  /// <summary>
31  /// Creates a new argument within one function-defining branch of a symbolic expression tree.
32  /// As described in Koza, Bennett, Andre, Keane, Genetic Programming III - Darwinian Invention and Problem Solving, 1999, pp. 106
33  /// </summary>
34  [Item("ArgumentCreater", "Manipulates a symbolic expression by creating a new argument within one function-defining branch.")]
35  [StorableClass]
36  public sealed class ArgumentCreater : SymbolicExpressionTreeArchitectureManipulator {
37    public override sealed void ModifyArchitecture(
38      IRandom random,
39      SymbolicExpressionTree symbolicExpressionTree,
40      ISymbolicExpressionGrammar grammar,
41      IntValue maxTreeSize, IntValue maxTreeHeight,
42      IntValue maxFunctionDefiningBranches, IntValue maxFunctionArguments,
43      out bool success) {
44      success = CreateNewArgument(random, symbolicExpressionTree, grammar, maxTreeSize.Value, maxTreeHeight.Value, maxFunctionDefiningBranches.Value, maxFunctionArguments.Value);
45    }
46
47    public static bool CreateNewArgument(
48      IRandom random,
49      SymbolicExpressionTree symbolicExpressionTree,
50      ISymbolicExpressionGrammar grammar,
51      int maxTreeSize, int maxTreeHeight,
52      int maxFunctionDefiningBranches, int maxFunctionArguments) {
53
54      var functionDefiningBranches = symbolicExpressionTree.IterateNodesPrefix().OfType<DefunTreeNode>();
55
56      if (functionDefiningBranches.Count() == 0)
57        // no function defining branch found => abort
58        return false;
59
60      // select a random function defining branch
61      var selectedDefunBranch = functionDefiningBranches.SelectRandom(random);
62      var definedArguments = (from symbol in selectedDefunBranch.Grammar.Symbols.OfType<Argument>()
63                              select symbol.ArgumentIndex).Distinct();
64      if (definedArguments.Count() >= maxFunctionArguments)
65        // max number of arguments reached => abort
66        return false;
67      // select a random cut point in the function defining branch
68      // the branch at the cut point is to be replaced by a new argument node
69      var cutPoints = (from node in selectedDefunBranch.IterateNodesPrefix()
70                       where node.SubTrees.Count > 0
71                       from subtree in node.SubTrees
72                       select new { Parent = node, ReplacedChildIndex = node.SubTrees.IndexOf(subtree), ReplacedChild = subtree }).ToList();
73
74      if (cutPoints.Count() == 0)
75        // no cut point found => abort;
76        return false;
77      var selectedCutPoint = cutPoints[random.Next(cutPoints.Count)];
78      var allowedArgumentIndexes = Enumerable.Range(0, maxFunctionArguments);
79      var newArgumentIndex = allowedArgumentIndexes.Except(definedArguments).First();
80      // replace the branch at the cut point with an argument node
81      var newArgNode = MakeArgumentNode(newArgumentIndex);
82      var replacedBranch = selectedCutPoint.ReplacedChild;
83      selectedCutPoint.Parent.RemoveSubTree(selectedCutPoint.ReplacedChildIndex);
84      selectedCutPoint.Parent.InsertSubTree(selectedCutPoint.ReplacedChildIndex, newArgNode);
85
86      // find all invocations of the selected ADF and attach a cloned version of the replaced branch (with all argument-nodes expanded)
87      var invocationNodes = from node in symbolicExpressionTree.IterateNodesPrefix().OfType<InvokeFunctionTreeNode>()
88                            where node.Symbol.FunctionName == selectedDefunBranch.FunctionName
89                            where node.SubTrees.Count == selectedDefunBranch.NumberOfArguments
90                            select node;
91      // do this repeatedly until no matching invocations are found     
92      while (invocationNodes.Count() > 0) {
93        List<SymbolicExpressionTreeNode> newlyAddedBranches = new List<SymbolicExpressionTreeNode>();
94        foreach (var invocationNode in invocationNodes) {
95          // append a new argument branch after expanding all argument nodes
96          var clonedBranch = (SymbolicExpressionTreeNode)replacedBranch.Clone();
97          clonedBranch = ReplaceArgumentsInBranch(clonedBranch, invocationNode.SubTrees);
98          invocationNode.InsertSubTree(newArgumentIndex, clonedBranch);
99          newlyAddedBranches.Add(clonedBranch);
100        }
101        invocationNodes = from newlyAddedBranch in newlyAddedBranches
102                          from node in newlyAddedBranch.IterateNodesPrefix().OfType<InvokeFunctionTreeNode>()
103                          where node.Symbol.FunctionName == selectedDefunBranch.FunctionName
104                          where node.SubTrees.Count == selectedDefunBranch.NumberOfArguments
105                          select node;
106      }
107      // increase expected number of arguments of function defining branch
108      // it's possible that the number of actually referenced arguments was reduced (all references were replaced by a single new argument)
109      // but the number of expected arguments is increased anyway
110      selectedDefunBranch.NumberOfArguments++;
111      selectedDefunBranch.Grammar.AddSymbol(newArgNode.Symbol);
112      selectedDefunBranch.Grammar.SetMinSubtreeCount(newArgNode.Symbol, 0);
113      selectedDefunBranch.Grammar.SetMaxSubtreeCount(newArgNode.Symbol, 0);
114      // allow the argument as child of any other symbol
115      foreach (var symb in selectedDefunBranch.Grammar.Symbols)
116        for (int i = 0; i < selectedDefunBranch.Grammar.GetMaxSubtreeCount(symb); i++) {
117          selectedDefunBranch.Grammar.SetAllowedChild(symb, newArgNode.Symbol, i);
118        }
119      foreach (var subtree in symbolicExpressionTree.Root.SubTrees) {
120        // when the changed function is known in the branch then update the number of arguments
121        var matchingSymbol = subtree.Grammar.Symbols.OfType<InvokeFunction>().Where(s => s.FunctionName == selectedDefunBranch.FunctionName).SingleOrDefault();
122        if (matchingSymbol != null) {
123          subtree.Grammar.SetMinSubtreeCount(matchingSymbol, selectedDefunBranch.NumberOfArguments);
124          subtree.Grammar.SetMaxSubtreeCount(matchingSymbol, selectedDefunBranch.NumberOfArguments);
125          foreach (var child in subtree.GetAllowedSymbols(0)) {
126            for (int i = 0; i < subtree.Grammar.GetMaxSubtreeCount(matchingSymbol); i++) {
127              subtree.Grammar.SetAllowedChild(matchingSymbol, child, i);
128            }
129          }
130        }
131      }
132      return true;
133    }
134
135    private static SymbolicExpressionTreeNode ReplaceArgumentsInBranch(SymbolicExpressionTreeNode branch, IList<SymbolicExpressionTreeNode> argumentTrees) {
136      if (branch is ArgumentTreeNode) {
137        var argNode = branch as ArgumentTreeNode;
138        // replace argument nodes by a clone of the original subtree that provided the result for the argument node
139        return (SymbolicExpressionTreeNode)argumentTrees[argNode.Symbol.ArgumentIndex].Clone();
140      } else {
141        // call recursively for all subtree
142        List<SymbolicExpressionTreeNode> subtrees = new List<SymbolicExpressionTreeNode>(branch.SubTrees);
143        while (branch.SubTrees.Count > 0) branch.RemoveSubTree(0);
144        foreach (var subtree in subtrees) {
145          branch.AddSubTree(ReplaceArgumentsInBranch(subtree, argumentTrees));
146        }
147        return branch;
148      }
149    }
150
151    private static SymbolicExpressionTreeNode MakeArgumentNode(int argIndex) {
152      var node = (ArgumentTreeNode)(new Argument(argIndex)).CreateTreeNode();
153      return node;
154    }
155  }
156}
Note: See TracBrowser for help on using the repository browser.