Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 5046 was 5014, checked in by mkommend, 14 years ago

Corrected SubTreeCrossover and ReplaceBranchManipulation to handle MaxExpressionDepth correctly. Additionally MaxExpressionDepth < 3 is not allowed.
(ticket #1315).

File size: 9.9 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;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
31namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Crossovers {
32  /// <summary>
33  /// Takes two parent individuals P0 and P1 each. Selects a random node N0 of P0 and a random node N1 of P1.
34  /// And replaces the branch with root0 N0 in P0 with N1 from P1 if the tree-size limits are not violated.
35  /// When recombination with N0 and N1 would create a tree that is too large or invalid the operator randomly selects new N0 and N1
36  /// until a valid configuration is found.
37  /// </summary> 
38  [Item("SubtreeCrossover", "An operator which performs subtree swapping crossover.")]
39  [StorableClass]
40  public sealed class SubtreeCrossover : SymbolicExpressionTreeCrossover {
41    public IValueLookupParameter<PercentValue> InternalCrossoverPointProbabilityParameter {
42      get { return (IValueLookupParameter<PercentValue>)Parameters["InternalCrossoverPointProbability"]; }
43    }
44    [StorableConstructor]
45    private SubtreeCrossover(bool deserializing) : base(deserializing) { }
46    private SubtreeCrossover(SubtreeCrossover original, Cloner cloner) : base(original, cloner) { }
47    public SubtreeCrossover()
48      : base() {
49      Parameters.Add(new ValueLookupParameter<PercentValue>("InternalCrossoverPointProbability", "The probability to select an internal crossover point (instead of a leaf node).", new PercentValue(0.9)));
50    }
51
52    public override IDeepCloneable Clone(Cloner cloner) {
53      return new SubtreeCrossover(this, cloner);
54    }
55
56    protected override SymbolicExpressionTree Cross(IRandom random,
57      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
58      IntValue maxTreeSize, IntValue maxTreeHeight, out bool success) {
59      return Cross(random, parent0, parent1, InternalCrossoverPointProbabilityParameter.ActualValue.Value, maxTreeSize.Value, maxTreeHeight.Value, out success);
60    }
61
62    public static SymbolicExpressionTree Cross(IRandom random,
63      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
64      double internalCrossoverPointProbability, int maxTreeSize, int maxTreeHeight, out bool success) {
65      // select a random crossover point in the first parent
66      SymbolicExpressionTreeNode crossoverPoint0;
67      int replacedSubtreeIndex;
68      SelectCrossoverPoint(random, parent0, internalCrossoverPointProbability, maxTreeSize, maxTreeHeight, out crossoverPoint0, out replacedSubtreeIndex);
69
70      // calculate the max size and height that the inserted branch can have
71      int maxInsertedBranchSize = maxTreeSize - (parent0.Size - crossoverPoint0.SubTrees[replacedSubtreeIndex].GetSize());
72      int maxInsertedBranchHeight = maxTreeHeight - GetBranchLevel(parent0.Root, crossoverPoint0);
73
74      List<SymbolicExpressionTreeNode> allowedBranches = new List<SymbolicExpressionTreeNode>();
75      parent1.Root.ForEachNodePostfix((n) => {
76        if (n.GetSize() < maxInsertedBranchSize &&
77          n.GetHeight() < maxInsertedBranchHeight &&
78          IsMatchingPointType(crossoverPoint0, replacedSubtreeIndex, n))
79          allowedBranches.Add(n);
80      });
81
82      if (allowedBranches.Count == 0) {
83        success = false;
84        return parent0;
85      } else {
86        var selectedBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);
87
88        // manipulate the tree of parent0 in place
89        // replace the branch in tree0 with the selected branch from tree1
90        crossoverPoint0.RemoveSubTree(replacedSubtreeIndex);
91        crossoverPoint0.InsertSubTree(replacedSubtreeIndex, selectedBranch);
92        success = true;
93        return parent0;
94      }
95    }
96
97    private static bool IsMatchingPointType(SymbolicExpressionTreeNode parent, int replacedSubtreeIndex, SymbolicExpressionTreeNode branch) {
98      // check syntax constraints of direct parent - child relation
99      if (!parent.Grammar.ContainsSymbol(branch.Symbol) ||
100          !parent.Grammar.IsAllowedChild(parent.Symbol, branch.Symbol, replacedSubtreeIndex)) return false;
101
102      bool result = true;
103      // check point type for the whole branch
104      branch.ForEachNodePostfix((n) => {
105        result =
106          result &&
107          parent.Grammar.ContainsSymbol(n.Symbol) &&
108          n.SubTrees.Count >= parent.Grammar.GetMinSubtreeCount(n.Symbol) &&
109          n.SubTrees.Count <= parent.Grammar.GetMaxSubtreeCount(n.Symbol);
110      });
111      return result;
112    }
113
114    private static void SelectCrossoverPoint(IRandom random, SymbolicExpressionTree parent0, double internalNodeProbability, int maxBranchSize, int maxBranchHeight, out SymbolicExpressionTreeNode crossoverPoint, out int subtreeIndex) {
115      if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
116      List<CrossoverPoint> internalCrossoverPoints = new List<CrossoverPoint>();
117      List<CrossoverPoint> leafCrossoverPoints = new List<CrossoverPoint>();
118      parent0.Root.ForEachNodePostfix((n) => {
119        if (n.SubTrees.Count > 0 &&
120          n.GetSize() < maxBranchSize &&
121          n.GetHeight() < maxBranchHeight &&
122          n != parent0.Root
123          ) {
124          foreach (var child in n.SubTrees) {
125            if (child.SubTrees.Count > 0)
126              internalCrossoverPoints.Add(new CrossoverPoint(n, child));
127            else
128              leafCrossoverPoints.Add(new CrossoverPoint(n, child));
129          }
130        }
131      });
132      if (random.NextDouble() < internalNodeProbability) {
133        // select from internal node if possible
134        if (internalCrossoverPoints.Count > 0) {
135          // select internal crossover point or leaf
136          var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
137          crossoverPoint = selectedCrossoverPoint.Parent;
138          subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
139        } else {
140          // otherwise select external node
141          var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
142          crossoverPoint = selectedCrossoverPoint.Parent;
143          subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
144        }
145      } else if (leafCrossoverPoints.Count > 0) {
146        // select from leaf crossover point if possible
147        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
148        crossoverPoint = selectedCrossoverPoint.Parent;
149        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
150      } else {
151        // otherwise select internal crossover point
152        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
153        crossoverPoint = selectedCrossoverPoint.Parent;
154        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
155      }
156    }
157
158    private static SymbolicExpressionTreeNode SelectRandomBranch(IRandom random, IEnumerable<SymbolicExpressionTreeNode> branches, double internalNodeProbability) {
159      if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
160      List<SymbolicExpressionTreeNode> allowedInternalBranches;
161      List<SymbolicExpressionTreeNode> allowedLeafBranches;
162      if (random.NextDouble() < internalNodeProbability) {
163        // select internal node if possible
164        allowedInternalBranches = (from branch in branches
165                                   where branch.SubTrees.Count > 0
166                                   select branch).ToList();
167        if (allowedInternalBranches.Count > 0) {
168          return allowedInternalBranches.SelectRandom(random);
169        } else {
170          // no internal nodes allowed => select leaf nodes
171          allowedLeafBranches = (from branch in branches
172                                 where branch.SubTrees.Count == 0
173                                 select branch).ToList();
174          return allowedLeafBranches.SelectRandom(random);
175        }
176      } else {
177        // select leaf node if possible
178        allowedLeafBranches = (from branch in branches
179                               where branch.SubTrees.Count == 0
180                               select branch).ToList();
181        if (allowedLeafBranches.Count > 0) {
182          return allowedLeafBranches.SelectRandom(random);
183        } else {
184          allowedInternalBranches = (from branch in branches
185                                     where branch.SubTrees.Count > 0
186                                     select branch).ToList();
187          return allowedInternalBranches.SelectRandom(random);
188        }
189      }
190    }
191
192    private static int GetBranchLevel(SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode point) {
193      if (root == point) return 0;
194      foreach (var subtree in root.SubTrees) {
195        int branchLevel = GetBranchLevel(subtree, point);
196        if (branchLevel < int.MaxValue) return 1 + branchLevel;
197      }
198      return int.MaxValue;
199    }
200  }
201}
Note: See TracBrowser for help on using the repository browser.