#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeuristicLab.Core;
using HeuristicLab.Operators;
using HeuristicLab.Random;
using HeuristicLab.Data;
using HeuristicLab.Constraints;
using System.Diagnostics;
namespace HeuristicLab.GP {
///
/// Implementation of a size fair crossover operator as described in:
/// William B. Langdon
/// Size Fair and Homologous Tree Genetic Programming Crossovers,
/// Genetic Programming and Evolvable Machines, Vol. 1, Number 1/2, pp. 95-119, April 2000
///
public class SizeFairCrossOver : SizeConstrictedGPCrossoverBase {
private int MaxRecombinationTries { get { return 20; } }
// private data structure for crossover points
protected class CrossoverPoint {
public IFunctionTree tree;
public int branchSize;
public List trail;
}
internal override IFunctionTree Cross(TreeGardener gardener, IRandom random, IFunctionTree tree0, IFunctionTree tree1, int maxTreeSize, int maxTreeHeight) {
int tries = 0;
IFunctionTree insertedBranch = null;
IFunctionTree parent = null;
int removedBranchIndex = 0;
do {
// select a random suboperator of the 'receiving' tree
while (parent == null) parent = gardener.GetRandomParentNode(tree0);
removedBranchIndex = random.Next(parent.SubTrees.Count);
insertedBranch = GetReplacementBranch((MersenneTwister)random, gardener, tree0, parent, removedBranchIndex, tree1, maxTreeSize, maxTreeHeight);
} while (insertedBranch == null && tries++ < MaxRecombinationTries);
if (insertedBranch != null) {
// replace the branch below the crossoverpoint with the selected branch from root1
parent.RemoveSubTree(removedBranchIndex);
parent.InsertSubTree(removedBranchIndex, insertedBranch);
}
return tree0;
}
private IFunctionTree GetReplacementBranch(MersenneTwister random, TreeGardener gardener, IFunctionTree intoTree, IFunctionTree parent, int replacedBranchIndex, IFunctionTree fromTree, int maxTreeSize, int maxTreeHeight) {
IList allowedFunctions = gardener.GetAllowedSubFunctions(parent.Function, replacedBranchIndex);
int removedBranchSize = parent.SubTrees[replacedBranchIndex].Size;
int maxBranchSize = maxTreeSize - (intoTree.Size - removedBranchSize);
int maxBranchHeight = maxTreeHeight - gardener.GetBranchLevel(intoTree, parent); // returns 1 if intoTree==parent and 2 if parent is a child of intoTree
List replacedTrail = GetTrail(intoTree, parent);
replacedTrail.Add(replacedBranchIndex);
List shorterBranches = new List();
List longerBranches = new List();
List equalLengthBranches = new List();
FindPossibleBranches(fromTree, allowedFunctions, maxBranchSize, maxBranchHeight, removedBranchSize, shorterBranches, equalLengthBranches, longerBranches, new List());
if (shorterBranches.Count > 0 && longerBranches.Count > 0) {
double pEqualLength = equalLengthBranches.Count > 0 ? 1.0 / removedBranchSize : 0.0;
double pLonger;
if (parent.Size == maxTreeSize) {
pLonger = 0.0;
} else {
pLonger = (1.0 - pEqualLength) / (longerBranches.Count * (1.0 + longerBranches.Average(p => p.branchSize) / shorterBranches.Average(p => p.branchSize)));
}
double pShorter = (1.0 - pEqualLength - pLonger);
double r = random.NextDouble();
if (r < pLonger) {
return SelectReplacement(random, replacedTrail, longerBranches);
} else if (r < pLonger + pShorter) {
return SelectReplacement(random, replacedTrail, shorterBranches);
} else {
return SelectReplacement(random, replacedTrail, equalLengthBranches);
}
} else if (equalLengthBranches.Count > 0) {
return SelectReplacement(random, replacedTrail, equalLengthBranches);
} else {
return null;
}
}
protected virtual IFunctionTree SelectReplacement(MersenneTwister random, List replacedTrail, List crossoverPoints) {
return crossoverPoints[random.Next(crossoverPoints.Count)].tree;
}
private void FindPossibleBranches(IFunctionTree tree, IList allowedFunctions, int maxBranchSize, int maxBranchHeight, int removedBranchSize,
List shorterBranches, List equalLengthBranches, List longerBranches, List trail) {
int treeSize = tree.Size;
if (allowedFunctions.Contains(tree.Function) && treeSize <= maxBranchSize && tree.Height <= maxBranchHeight) {
CrossoverPoint p = new CrossoverPoint();
p.branchSize = treeSize;
p.tree = tree;
p.trail = new List(trail);
if (treeSize < removedBranchSize) shorterBranches.Add(p);
else if (treeSize > removedBranchSize) longerBranches.Add(p);
else equalLengthBranches.Add(p);
}
for (int i = 0; i < tree.SubTrees.Count; i++) {
trail.Add(i);
FindPossibleBranches(tree.SubTrees[i], allowedFunctions, maxBranchSize, maxBranchHeight, removedBranchSize, shorterBranches, equalLengthBranches, longerBranches, trail);
trail.RemoveAt(trail.Count - 1);
}
}
private List GetTrail(IFunctionTree root, IFunctionTree branch) {
List trail = new List();
GetTrail(root, branch, trail);
trail.Reverse();
trail.RemoveAt(trail.Count - 1);
return trail;
}
private void GetTrail(IFunctionTree root, IFunctionTree branch, List trail) {
if (root == branch) {
trail.Add(-1); // add flag that there was a match
return;
}
for (int i = 0; i < root.SubTrees.Count; i++) {
GetTrail(root.SubTrees[i], branch, trail);
if (trail.Count > 0) {
trail.Add(i);
return;
}
}
}
}
}