Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.GP.Operators/3.3/Recombination/UniformCrossover.cs @ 3091

Last change on this file since 3091 was 2222, checked in by gkronber, 15 years ago

Merged changes from GP-refactoring branch back into the trunk #713.

File size: 7.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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.GP.Interfaces;
25
26namespace HeuristicLab.GP.Operators {
27  /// <summary>
28  /// Implementation of a homologous uniform crossover operator as described in:
29  /// R. Poli and W. B. Langdon.  On the Search Properties of Different Crossover Operators in Genetic Programming.
30  /// In Proceedings of Genetic Programming '98, Madison, Wisconsin, 1998.
31  /// </summary>
32  public class UniformCrossover : SizeConstrictedGPCrossoverBase {
33    // internal datastructure to represent crossover points
34    private class CrossoverPoint {
35      public IFunctionTree Parent0;
36      public IFunctionTree Parent1;
37      public int ChildIndex;
38      public bool IsInternal;
39    }
40
41    public override string Description {
42      get {
43        return @"Uniform crossover as defined by Poli and Langdon";
44      }
45    }
46
47    internal override IFunctionTree Cross(TreeGardener gardener, IRandom random, IFunctionTree tree0, IFunctionTree tree1, int maxTreeSize, int maxTreeHeight) {
48      List<CrossoverPoint> allowedCrossOverPoints = new List<CrossoverPoint>();
49      GetCrossOverPoints(gardener, tree0, tree1, allowedCrossOverPoints);
50      // iterate through the list of crossover points and swap nodes with p=0.5
51      foreach (CrossoverPoint crossoverPoint in allowedCrossOverPoints) {
52        if (random.NextDouble() < 0.5) {
53          if (crossoverPoint.IsInternal) {
54            ExchangeNodes(crossoverPoint);
55          } else {
56            SwapSubtrees(crossoverPoint);
57          }
58        }
59      }
60      return tree0;
61    }
62
63    private void GetCrossOverPoints(TreeGardener gardener, IFunctionTree branch0, IFunctionTree branch1, List<CrossoverPoint> crossoverPoints) {
64      if (branch0.SubTrees.Count != branch1.SubTrees.Count) return; // branches have to have same number of sub-trees to be valid crossover points
65      // iterate over all sub-trees
66      for (int i = 0; i < branch0.SubTrees.Count; i++) {
67        IFunctionTree currentSubTree0 = branch0.SubTrees[i];
68        IFunctionTree currentSubTree1 = branch1.SubTrees[i];
69        // when the current sub-tree in branch1 can be attached as a child of branch0
70        // and the sub-tree of branch0 can be attached as child of branch1.
71        // note: we have to check both cases because either branch0 or branch1 can end up in the result tree
72        if (gardener.GetAllowedSubFunctions(branch0.Function, i).Contains(currentSubTree1.Function) &&
73          gardener.GetAllowedSubFunctions(branch1.Function, i).Contains(currentSubTree0.Function)) {
74          // and the sub-tree is at the border of the common region
75          if (currentSubTree0.SubTrees.Count != currentSubTree1.SubTrees.Count) {
76            // then we have found a valid crossover point
77            CrossoverPoint p = new CrossoverPoint();
78            p.ChildIndex = i;
79            p.Parent0 = branch0;
80            p.Parent1 = branch1;
81            p.IsInternal = false;
82            crossoverPoints.Add(p);
83          } else {
84            // when the sub-trees are not on the border of the common region
85            // we also have to check if the children of the current sub-trees of branch0 and branch1 can be exchanged
86            if (CanHaveSubTrees(gardener, currentSubTree0, currentSubTree1.SubTrees) &&
87              CanHaveSubTrees(gardener, currentSubTree1, currentSubTree0.SubTrees)) {
88              CrossoverPoint p = new CrossoverPoint();
89              p.ChildIndex = i;
90              p.Parent0 = branch0;
91              p.Parent1 = branch1;
92              p.IsInternal = true;
93              crossoverPoints.Add(p);
94            }
95          }
96        }
97        GetCrossOverPoints(gardener, currentSubTree0, currentSubTree1, crossoverPoints);
98      }
99    }
100
101    private bool CanHaveSubTrees(TreeGardener gardener, IFunctionTree parent, IList<IFunctionTree> subTrees) {
102      for (int i = 0; i < subTrees.Count; i++) {
103        if (!gardener.GetAllowedSubFunctions(parent.Function, i).Contains(subTrees[i].Function)) return false;
104      }
105      return true;
106    }
107
108    private void ExchangeNodes(CrossoverPoint crossoverPoint) {
109      IFunctionTree parent0 = crossoverPoint.Parent0;
110      IFunctionTree parent1 = crossoverPoint.Parent1;
111      int childIndex = crossoverPoint.ChildIndex;
112      IFunctionTree branch0 = crossoverPoint.Parent0.SubTrees[childIndex];
113      IFunctionTree branch1 = crossoverPoint.Parent1.SubTrees[childIndex];
114      // exchange the branches in the parent
115      parent0.RemoveSubTree(childIndex);
116      parent0.InsertSubTree(childIndex, branch1);
117      parent1.RemoveSubTree(childIndex);
118      parent1.InsertSubTree(childIndex, branch0);
119
120      ExchangeChildren(branch0, branch1);
121    }
122
123    private void SwapSubtrees(CrossoverPoint crossoverPoint) {
124      IFunctionTree parent0 = crossoverPoint.Parent0;
125      IFunctionTree parent1 = crossoverPoint.Parent1;
126      int childIndex = crossoverPoint.ChildIndex;
127      IFunctionTree branch0 = crossoverPoint.Parent0.SubTrees[childIndex];
128      IFunctionTree branch1 = crossoverPoint.Parent1.SubTrees[childIndex];
129      // insert branch1 into parent0 replacing branch0
130      parent0.RemoveSubTree(childIndex);
131      parent0.InsertSubTree(childIndex, branch1);
132      // insert branch0 into parent1 replacing branch1
133      parent1.RemoveSubTree(childIndex);
134      parent1.InsertSubTree(childIndex, branch0);
135    }
136
137    private void ExchangeChildren(IFunctionTree branch0, IFunctionTree branch1) {
138      List<IFunctionTree> branch0Children = new List<IFunctionTree>(branch0.SubTrees); // lists to backup subtrees
139      List<IFunctionTree> branch1Children = new List<IFunctionTree>(branch1.SubTrees);
140
141      // remove children of branch0 and branch1
142      while (branch1.SubTrees.Count > 0) branch1.RemoveSubTree(0);
143      while (branch0.SubTrees.Count > 0) branch0.RemoveSubTree(0);
144
145      // add original children of branch0 to branch1
146      foreach (IFunctionTree subTree in branch0Children) {
147        branch1.AddSubTree(subTree);
148      }
149      // add original children of branch1 to branch0
150      foreach (IFunctionTree subTree in branch1Children) {
151        branch0.AddSubTree(subTree);
152      }
153    }
154  }
155}
Note: See TracBrowser for help on using the repository browser.