Free cookie consent management tool by TermsFeed Policy Generator

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

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

Improved LINQ statements in SubtreeCrossover to make them more efficient. #938

File size: 9.1 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      var allowedBranches = (from branch in parent1.Root.IterateNodesPostfix()
70                             where branch.GetSize() < maxInsertedBranchSize
71                             where branch.GetHeight() < maxInsertedBranchHeight
72                             where IsMatchingPointType(crossoverPoint0, replacedSubtreeIndex, branch)
73                             select branch).ToList();
74
75      if (allowedBranches.Count() == 0) {
76        success = false;
77        return parent0;
78      } else {
79        var selectedBranch = SelectRandomBranch(random, allowedBranches, internalCrossoverPointProbability);
80
81        // manipulate the tree of parent0 in place
82        // replace the branch in tree0 with the selected branch from tree1
83        crossoverPoint0.RemoveSubTree(replacedSubtreeIndex);
84        crossoverPoint0.InsertSubTree(replacedSubtreeIndex, selectedBranch);
85        success = true;
86        return parent0;
87      }
88    }
89
90    private static bool IsMatchingPointType(SymbolicExpressionTreeNode parent, int replacedSubtreeIndex, SymbolicExpressionTreeNode branch) {
91      // check point type for the whole branch
92      foreach (var node in branch.IterateNodesPostfix()) {
93        if (!parent.Grammar.ContainsSymbol(node.Symbol)) return false;
94        else if (node.SubTrees.Count < parent.Grammar.GetMinSubtreeCount(node.Symbol)) return false;
95        else if (node.SubTrees.Count > parent.Grammar.GetMaxSubtreeCount(node.Symbol)) return false;
96      }
97
98      // check syntax constraints of direct parent - child relation
99      if (!parent.Grammar.IsAllowedChild(parent.Symbol, branch.Symbol, replacedSubtreeIndex)) return false;
100
101      return true;
102    }
103
104    private static void SelectCrossoverPoint(IRandom random, SymbolicExpressionTree parent0, double internalNodeProbability, int maxBranchSize, int maxBranchHeight, out SymbolicExpressionTreeNode crossoverPoint, out int subtreeIndex) {
105      var crossoverPoints = (from branch in parent0.Root.IterateNodesPostfix()
106                             where branch.SubTrees.Count > 0
107                             where branch != parent0.Root
108                             where branch.GetSize() < maxBranchSize
109                             where branch.GetHeight() < maxBranchHeight
110                             from index in Enumerable.Range(0, branch.SubTrees.Count)
111                             let p = new { CrossoverPoint = branch, SubtreeIndex = index, IsLeaf = branch.SubTrees[index].SubTrees.Count == 0 }
112                             select p).ToList();
113      var internalCrossoverPoints = (from p in crossoverPoints
114                                     where !p.IsLeaf
115                                     select p).ToList();
116      var leafCrossoverPoints = (from p in crossoverPoints
117                                 where p.IsLeaf
118                                 select p).ToList();
119      if (internalCrossoverPoints.Count == 0) {
120        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
121        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
122        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
123      } else if (leafCrossoverPoints.Count == 0) {
124        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
125        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
126        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
127      } else if (random.NextDouble() < internalNodeProbability && internalCrossoverPoints.Count > 0) {
128        // select internal crossover point or leaf
129        var selectedCrossoverPoint = internalCrossoverPoints[random.Next(internalCrossoverPoints.Count)];
130        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
131        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
132      } else {
133        var selectedCrossoverPoint = leafCrossoverPoints[random.Next(leafCrossoverPoints.Count)];
134        crossoverPoint = selectedCrossoverPoint.CrossoverPoint;
135        subtreeIndex = selectedCrossoverPoint.SubtreeIndex;
136      }
137    }
138
139    private static SymbolicExpressionTreeNode SelectRandomBranch(IRandom random, IEnumerable<SymbolicExpressionTreeNode> branches, double internalNodeProbability) {
140      if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
141      var allowedInternalBranches = (from branch in branches
142                                     where branch.SubTrees.Count > 0
143                                     select branch).ToList();
144      var allowedLeafBranches = (from branch in branches
145                                 where branch.SubTrees.Count == 0
146                                 select branch).ToList();
147      if (allowedInternalBranches.Count == 0) {
148        return allowedLeafBranches.SelectRandom(random);
149      } else if (allowedLeafBranches.Count == 0) {
150        return allowedInternalBranches.SelectRandom(random);
151      } else if (random.NextDouble() < internalNodeProbability) {
152        // when leaf and internal nodes are possible then choose either a leaf or internal node with internalNodeProbability
153        return allowedInternalBranches.SelectRandom(random);
154      } else {
155        return allowedLeafBranches.SelectRandom(random);
156      }
157    }
158
159    private static int GetBranchLevel(SymbolicExpressionTreeNode root, SymbolicExpressionTreeNode point) {
160      if (root == point) return 0;
161      foreach (var subtree in root.SubTrees) {
162        int branchLevel = GetBranchLevel(subtree, point);
163        if (branchLevel < int.MaxValue) return 1 + branchLevel;
164      }
165      return int.MaxValue;
166    }
167  }
168}
Note: See TracBrowser for help on using the repository browser.