Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.3/Crossovers/SubtreeCrossover.cs @ 3297

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

Added test classes for crossover and subroutine creater. #290 (Implement ADFs)

File size: 10.3 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 HeuristicLab.Core;
24using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
25using HeuristicLab.Data;
26using System.Linq;
27using System;
28using HeuristicLab.Parameters;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.GeneralSymbols;
30namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
31
32
33  /// <summary>
34  /// Takes two parent individuals P0 and P1 each. Selects a random node N0 of P0 and a random node N1 of P1.
35  /// And replaces the branch with root0 N0 in P0 with N1 from P1 if the tree-size limits are not violated.
36  /// When recombination with N0 and N1 would create a tree that is too large or invalid the operator randomly selects new N0 and N1
37  /// until a valid configuration is found.
38  /// </summary> 
39  [Item("SubtreeCrossover", "An operator which performs subtree swapping crossover.")]
40  [StorableClass]
41  public class SubtreeCrossover : SymbolicExpressionTreeCrossover {
42    public IValueLookupParameter<PercentValue> InternalCrossoverPointProbabilityParameter {
43      get { return (IValueLookupParameter<PercentValue>)Parameters["InternalCrossoverPointProbability"]; }
44    }
45
46    public SubtreeCrossover()
47      : base() {
48      Parameters.Add(new ValueLookupParameter<PercentValue>("InternalCrossoverPointProbability", "The probability to select an internal crossover point (instead of a leaf node).", new PercentValue(0.9)));
49    }
50
51    protected override SymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionGrammar grammar,
52      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
53      IntValue maxTreeSize, IntValue maxTreeHeight, out bool success) {
54      return Cross(random, grammar, parent0, parent1, InternalCrossoverPointProbabilityParameter.ActualValue.Value, maxTreeSize.Value, maxTreeHeight.Value, out success);
55    }
56
57    public static SymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionGrammar grammar,
58      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
59      double internalCrossoverPointProbability, int maxTreeSize, int maxTreeHeight, out bool success) {
60      // select a random crossover point in the first parent
61      SymbolicExpressionTreeNode crossoverPoint0;
62      int replacedSubtreeIndex;
63      SelectCrossoverPoint(random, parent0, internalCrossoverPointProbability, out crossoverPoint0, out replacedSubtreeIndex);
64
65      // calculate the max size and height that the inserted branch can have
66      int maxInsertedBranchSize = maxTreeSize - (parent0.Size - crossoverPoint0.SubTrees[replacedSubtreeIndex].GetSize());
67      int maxInsertedBranchHeight = maxTreeHeight - GetBranchLevel(parent0.Root, crossoverPoint0);
68
69      var allowedBranches = from branch in IterateNodes(parent1.Root)
70                            where branch.GetSize() < maxInsertedBranchSize
71                            where branch.GetHeight() < maxInsertedBranchHeight
72                            where grammar.GetAllowedSymbols(crossoverPoint0.Symbol, replacedSubtreeIndex).Contains(branch.Symbol)
73                            where IsMatchingPointType(parent0, crossoverPoint0, branch)
74                            select branch;
75
76      if (allowedBranches.Count() == 0) {
77        success = false;
78        return parent0;
79      } else {
80        var selectedBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);
81
82        // manipulate the tree of parent0 in place
83        // replace the branch in tree0 with the selected branch from tree1
84        crossoverPoint0.RemoveSubTree(replacedSubtreeIndex);
85        crossoverPoint0.InsertSubTree(replacedSubtreeIndex, selectedBranch);
86        success = true;
87        return parent0;
88      }
89    }
90
91    private static bool IsMatchingPointType(SymbolicExpressionTree tree, SymbolicExpressionTreeNode parent, SymbolicExpressionTreeNode newBranch) {
92      var functionCalls = (from node in IterateNodes(newBranch)
93                           let invokeNode = node as InvokeFunctionTreeNode
94                           let argNode = node as ArgumentTreeNode
95                           where invokeNode != null || argNode != null
96                           let name = invokeNode != null ? invokeNode.InvokedFunctionName : "ARG" + argNode.ArgumentIndex
97                           let argCount = invokeNode != null ? invokeNode.SubTrees.Count : 0
98                           select new { FunctionName = name, FunctionArgumentCount = argCount }).Distinct();
99      var definingBranch = GetDefiningBranch(tree, parent);
100      if (definingBranch == null) return false;
101      foreach (var functionCall in functionCalls) {
102        if (!definingBranch.DynamicSymbols.Contains(functionCall.FunctionName) ||
103          definingBranch.GetDynamicSymbolArgumentCount(functionCall.FunctionName) != functionCall.FunctionArgumentCount)
104          return false;
105      }
106      return true;
107    }
108
109    private static SymbolicExpressionTreeNode GetDefiningBranch(SymbolicExpressionTree tree, SymbolicExpressionTreeNode parent) {
110      foreach (var treeNode in tree.Root.SubTrees) {
111        if (IterateNodes(treeNode).Contains(parent)) return treeNode;
112      }
113      return null;
114    }
115
116    private static void SelectCrossoverPoint(IRandom random, SymbolicExpressionTree parent0, double internalNodeProbability, out SymbolicExpressionTreeNode crossoverPoint, out int subtreeIndex) {
117      var crossoverPoints = from branch in IterateNodes(parent0.Root)
118                            where branch.SubTrees.Count > 0
119                            where !(branch.Symbol is ProgramRootSymbol)
120                            from index in Enumerable.Range(0, branch.SubTrees.Count)
121                            let p = new { CrossoverPoint = branch, SubtreeIndex = index, IsLeaf = branch.SubTrees[index].SubTrees.Count == 0 }
122                            select p;
123      var internalCrossoverPoints = (from p in crossoverPoints
124                                     where !p.IsLeaf
125                                     select p).ToList();
126      var leafCrossoverPoints = (from p in crossoverPoints
127                                 where p.IsLeaf
128                                 select p).ToList();
129      if (internalCrossoverPoints.Count == 0) {
130        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
131        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
132        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
133      } else if (leafCrossoverPoints.Count == 0) {
134        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
135        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
136        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
137      } else if (random.NextDouble() < internalNodeProbability && internalCrossoverPoints.Count > 0) {
138        // select internal crossover point or leaf
139        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
140        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
141        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
142      } else {
143        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
144        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
145        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
146      }
147    }
148
149    private static SymbolicExpressionTreeNode SelectRandomBranch(IRandom random, IEnumerable<SymbolicExpressionTreeNode> branches, double internalNodeProbability) {
150      if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
151      var groupedBranches = from branch in branches
152                            group branch by branch.SubTrees.Count into g
153                            select g;
154      var allowedInternalBranches = (from g in groupedBranches
155                                     where g.Key > 0
156                                     from branch in g
157                                     select branch).ToList();
158      var allowedLeafBranches = (from g in groupedBranches
159                                 where g.Key == 0
160                                 from leaf in g
161                                 select leaf).ToList();
162      if (allowedInternalBranches.Count == 0) {
163        return allowedLeafBranches[random.Next(allowedLeafBranches.Count)];
164      } else if (allowedLeafBranches.Count == 0) {
165        return allowedInternalBranches[random.Next(allowedInternalBranches.Count)];
166      } else if (random.NextDouble() < internalNodeProbability) {
167        // when leaf and internal nodes are possible then choose either a leaf or internal node with internalNodeProbability
168        return allowedInternalBranches[random.Next(allowedInternalBranches.Count)];
169      } else {
170        return allowedLeafBranches[random.Next(allowedLeafBranches.Count)];
171      }
172    }
173
174    private static IEnumerable<SymbolicExpressionTreeNode> IterateNodes(SymbolicExpressionTreeNode root) {
175      foreach (var subTree in root.SubTrees) {
176        foreach (var branch in IterateNodes(subTree)) {
177          yield return branch;
178        }
179      }
180      yield return root;
181    }
182
183    private static int GetBranchLevel(SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode point) {
184      if (root == point) return 0;
185      foreach (var subtree in root.SubTrees) {
186        int branchLevel = GetBranchLevel(subtree, point);
187        if (branchLevel < int.MaxValue) return 1 + branchLevel;
188      }
189      return int.MaxValue;
190    }
191  }
192}
Note: See TracBrowser for help on using the repository browser.