Free cookie consent management tool by TermsFeed Policy Generator

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

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

Minor improvements concerning efficiency of symbolic expression tree encoding data structures and operators. #1073

File size: 9.6 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.Common;
24using HeuristicLab.Core;
25using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
26using HeuristicLab.Data;
27using System.Linq;
28using System;
29using HeuristicLab.Parameters;
30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
31
32namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Crossovers {
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,
52      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
53      IntValue maxTreeSize, IntValue maxTreeHeight, out bool success) {
54      return Cross(random, parent0, parent1, InternalCrossoverPointProbabilityParameter.ActualValue.Value, maxTreeSize.Value, maxTreeHeight.Value, out success);
55    }
56
57    public static SymbolicExpressionTree Cross(IRandom random,
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, maxTreeSize - 1, maxTreeHeight - 1, 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      List<SymbolicExpressionTreeNode> allowedBranches = new List<SymbolicExpressionTreeNode>();
70      parent1.Root.ForEachNodePostfix((n) => {
71        if (n.GetSize() < maxInsertedBranchSize &&
72          n.GetHeight() < maxInsertedBranchHeight &&
73          IsMatchingPointType(crossoverPoint0, replacedSubtreeIndex, n))
74          allowedBranches.Add(n);
75      });
76
77      if (allowedBranches.Count == 0) {
78        success = false;
79        return parent0;
80      } else {
81        var selectedBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);
82
83        // manipulate the tree of parent0 in place
84        // replace the branch in tree0 with the selected branch from tree1
85        crossoverPoint0.RemoveSubTree(replacedSubtreeIndex);
86        crossoverPoint0.InsertSubTree(replacedSubtreeIndex, selectedBranch);
87        success = true;
88        return parent0;
89      }
90    }
91
92    private static bool IsMatchingPointType(SymbolicExpressionTreeNode parent, int replacedSubtreeIndex, SymbolicExpressionTreeNode branch) {
93      // check syntax constraints of direct parent - child relation
94      if (!parent.Grammar.IsAllowedChild(parent.Symbol, branch.Symbol, replacedSubtreeIndex)) return false;
95
96      bool result = true;
97      // check point type for the whole branch
98      branch.ForEachNodePostfix((n) => {
99        result &= n.SubTrees.Count >= parent.Grammar.GetMinSubtreeCount(n.Symbol);
100        result &= n.SubTrees.Count <= parent.Grammar.GetMaxSubtreeCount(n.Symbol);
101        result &= parent.Grammar.ContainsSymbol(n.Symbol);
102      });
103      return result;
104    }
105
106    private static void SelectCrossoverPoint(IRandom random, SymbolicExpressionTree parent0, double internalNodeProbability, int maxBranchSize, int maxBranchHeight, out SymbolicExpressionTreeNode crossoverPoint, out int subtreeIndex) {
107      if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
108      List<CrossoverPoint> internalCrossoverPoints = new List<CrossoverPoint>();
109      List<CrossoverPoint> leafCrossoverPoints = new List<CrossoverPoint>();
110      parent0.Root.ForEachNodePostfix((n) => {
111        if (n.SubTrees.Count > 0 &&
112          n.GetSize() < maxBranchSize &&
113          n.GetHeight() < maxBranchHeight &&
114          n != parent0.Root
115          ) {
116          foreach (var child in n.SubTrees) {
117            if (child.SubTrees.Count > 0)
118              internalCrossoverPoints.Add(new CrossoverPoint(n, child));
119            else
120              leafCrossoverPoints.Add(new CrossoverPoint(n, child));
121          }
122        }
123      });
124      if (random.NextDouble() < internalNodeProbability) {
125        // select from internal node if possible
126        if (internalCrossoverPoints.Count > 0) {
127          // select internal crossover point or leaf
128          var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
129          crossoverPoint = selectedCrossoverPoint.Parent;
130          subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
131        } else {
132          // otherwise select external node
133          var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
134          crossoverPoint = selectedCrossoverPoint.Parent;
135          subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
136        }
137      } else if (leafCrossoverPoints.Count > 0) {
138        // select from leaf crossover point if possible
139        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
140        crossoverPoint = selectedCrossoverPoint.Parent;
141        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
142      } else {
143        // otherwise select internal crossover point
144        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
145        crossoverPoint = selectedCrossoverPoint.Parent;
146        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
147      }
148    }
149
150    private static SymbolicExpressionTreeNode SelectRandomBranch(IRandom random, IEnumerable<SymbolicExpressionTreeNode> branches, double internalNodeProbability) {
151      if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
152      List<SymbolicExpressionTreeNode> allowedInternalBranches;
153      List<SymbolicExpressionTreeNode> allowedLeafBranches;
154      if (random.NextDouble() < internalNodeProbability) {
155        // select internal node if possible
156        allowedInternalBranches = (from branch in branches
157                                   where branch.SubTrees.Count > 0
158                                   select branch).ToList();
159        if (allowedInternalBranches.Count > 0) {
160          return allowedInternalBranches.SelectRandom(random);
161        } else {
162          // no internal nodes allowed => select leaf nodes
163          allowedLeafBranches = (from branch in branches
164                                 where branch.SubTrees.Count == 0
165                                 select branch).ToList();
166          return allowedLeafBranches.SelectRandom(random);
167        }
168      } else {
169        // select leaf node if possible
170        allowedLeafBranches = (from branch in branches
171                               where branch.SubTrees.Count == 0
172                               select branch).ToList();
173        if (allowedLeafBranches.Count > 0) {
174          return allowedLeafBranches.SelectRandom(random);
175        } else {
176          allowedInternalBranches = (from branch in branches
177                                     where branch.SubTrees.Count > 0
178                                     select branch).ToList();
179          return allowedInternalBranches.SelectRandom(random);
180        }
181      }
182    }
183
184    private static int GetBranchLevel(SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode point) {
185      if (root == point) return 0;
186      foreach (var subtree in root.SubTrees) {
187        int branchLevel = GetBranchLevel(subtree, point);
188        if (branchLevel < int.MaxValue) return 1 + branchLevel;
189      }
190      return int.MaxValue;
191    }
192  }
193}
Note: See TracBrowser for help on using the repository browser.