Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 5367 was 5367, checked in by gkronber, 13 years ago

#1136 Fixed test cases for symbolic expression tree encoding operators (+ minor bug fixes in symbolic expression tree operators).

File size: 9.9 KB
RevLine 
[645]1#region License Information
2/* HeuristicLab
[3237]3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[645]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
[4068]22using System;
[645]23using System.Collections.Generic;
[4068]24using System.Linq;
[4722]25using HeuristicLab.Common;
[645]26using HeuristicLab.Core;
[3237]27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
[4068]29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
[645]30
[3462]31namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Crossovers {
[3237]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]
[4722]40  public sealed class SubtreeCrossover : SymbolicExpressionTreeCrossover {
[3237]41    public IValueLookupParameter<PercentValue> InternalCrossoverPointProbabilityParameter {
42      get { return (IValueLookupParameter<PercentValue>)Parameters["InternalCrossoverPointProbability"]; }
[645]43    }
[4722]44    [StorableConstructor]
45    private SubtreeCrossover(bool deserializing) : base(deserializing) { }
46    private SubtreeCrossover(SubtreeCrossover original, Cloner cloner) : base(original, cloner) { }
[3237]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
[4722]52    public override IDeepCloneable Clone(Cloner cloner) {
53      return new SubtreeCrossover(this, cloner);
54    }
55
[3338]56    protected override SymbolicExpressionTree Cross(IRandom random,
[3237]57      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
[3294]58      IntValue maxTreeSize, IntValue maxTreeHeight, out bool success) {
[3338]59      return Cross(random, parent0, parent1, InternalCrossoverPointProbabilityParameter.ActualValue.Value, maxTreeSize.Value, maxTreeHeight.Value, out success);
[3237]60    }
61
[3338]62    public static SymbolicExpressionTree Cross(IRandom random,
[3237]63      SymbolicExpressionTree parent0, SymbolicExpressionTree parent1,
[3294]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;
[5014]68      SelectCrossoverPoint(random, parent0, internalCrossoverPointProbability, maxTreeSize, maxTreeHeight, out crossoverPoint0, out replacedSubtreeIndex);
[645]69
[3294]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);
[645]73
[3997]74      List<SymbolicExpressionTreeNode> allowedBranches = new List<SymbolicExpressionTreeNode>();
75      parent1.Root.ForEachNodePostfix((n) => {
[5367]76        if (n.GetSize() <= maxInsertedBranchSize &&
77          n.GetHeight() <= maxInsertedBranchHeight &&
[3997]78          IsMatchingPointType(crossoverPoint0, replacedSubtreeIndex, n))
79          allowedBranches.Add(n);
80      });
[645]81
[3997]82      if (allowedBranches.Count == 0) {
[3297]83        success = false;
84        return parent0;
85      } else {
[3294]86        var selectedBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);
[645]87
[3294]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;
[645]94      }
95    }
96
[3338]97    private static bool IsMatchingPointType(SymbolicExpressionTreeNode parent, int replacedSubtreeIndex, SymbolicExpressionTreeNode branch) {
98      // check syntax constraints of direct parent - child relation
[4106]99      if (!parent.Grammar.ContainsSymbol(branch.Symbol) ||
100          !parent.Grammar.IsAllowedChild(parent.Symbol, branch.Symbol, replacedSubtreeIndex)) return false;
[3338]101
[3997]102      bool result = true;
103      // check point type for the whole branch
104      branch.ForEachNodePostfix((n) => {
[3998]105        result =
106          result &&
[4106]107          parent.Grammar.ContainsSymbol(n.Symbol) &&
[3998]108          n.SubTrees.Count >= parent.Grammar.GetMinSubtreeCount(n.Symbol) &&
[4106]109          n.SubTrees.Count <= parent.Grammar.GetMaxSubtreeCount(n.Symbol);
[3997]110      });
111      return result;
[3294]112    }
113
[3369]114    private static void SelectCrossoverPoint(IRandom random, SymbolicExpressionTree parent0, double internalNodeProbability, int maxBranchSize, int maxBranchHeight, out SymbolicExpressionTreeNode crossoverPoint, out int subtreeIndex) {
[3997]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) => {
[5367]119        if (n.SubTrees.Count > 0 && n != parent0.Root) {
[3997]120          foreach (var child in n.SubTrees) {
[5367]121            if (child.GetSize() <= maxBranchSize &&
122                child.GetHeight() <= maxBranchHeight) {
123              if (child.SubTrees.Count > 0)
124                internalCrossoverPoints.Add(new CrossoverPoint(n, child));
125              else
126                leafCrossoverPoints.Add(new CrossoverPoint(n, child));
127            }
[3997]128          }
129        }
130      });
[5367]131
[3997]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
[3294]147        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
[3997]148        crossoverPoint = selectedCrossoverPoint.Parent;
[3294]149        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
[3997]150      } else {
151        // otherwise select internal crossover point
[3237]152        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
[3997]153        crossoverPoint = selectedCrossoverPoint.Parent;
[3237]154        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
[645]155      }
156    }
[3237]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");
[3997]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
[3989]172                                 where branch.SubTrees.Count == 0
173                                 select branch).ToList();
[3997]174          return allowedLeafBranches.SelectRandom(random);
175        }
[3237]176      } else {
[3997]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        }
[3237]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    }
[645]200  }
201}
Note: See TracBrowser for help on using the repository browser.