#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 HeuristicLab.Core; using HeuristicLab.Random; using System.Diagnostics; using HeuristicLab.GP.Interfaces; namespace HeuristicLab.GP.Operators { public class SubstituteSubTreeManipulation : GPManipulatorBase { public override string Description { get { return "Selects a random node of the tree and replaces it with randomly initialized subtree."; } } public SubstituteSubTreeManipulation() : base() { } internal override IOperation Manipulate(MersenneTwister random, IGeneticProgrammingModel gpModel, FunctionLibrary library, int maxTreeSize, int maxTreeHeight, IScope scope) { TreeGardener gardener = new TreeGardener(random, library); IFunctionTree parent = gardener.GetRandomParentNode(gpModel.FunctionTree); if (parent == null) { // parent == null means we should subsitute the whole tree // => create a new random tree IFunctionTree newTree = gardener.CreateRandomTree(gardener.AllFunctions, maxTreeSize, maxTreeHeight); Debug.Assert(gardener.IsValidTree(newTree)); gpModel.FunctionTree = newTree; // return a CompositeOperation that randomly initializes the new tree return Util.CreateInitializationOperation(TreeGardener.GetAllSubTrees(newTree), scope); } else { // determine a random child of the parent to be replaced int childIndex = random.Next(parent.SubTrees.Count); // get the list of allowed functions for the new sub-tree ICollection allowedFunctions = gardener.GetAllowedSubFunctions(parent.Function, childIndex); if (allowedFunctions.Count == 0) { // don't change anything // this shouldn't happen throw new InvalidProgramException(); } // calculate the maximum size and height of the new sub-tree based on the location where // it will be inserted int parentLevel = gardener.GetBranchLevel(gpModel.FunctionTree, parent); int maxSubTreeHeight = maxTreeHeight - parentLevel; int maxSubTreeSize = maxTreeSize - (gpModel.Size - parent.SubTrees[childIndex].GetSize()); // create a random function tree IFunctionTree newTree = gardener.CreateRandomTree(allowedFunctions, maxSubTreeSize, maxSubTreeHeight); parent.RemoveSubTree(childIndex); parent.InsertSubTree(childIndex, newTree); Debug.Assert(gardener.IsValidTree(gpModel.FunctionTree)); // update the values of treeSize and treeHeight gpModel.Size = gpModel.FunctionTree.GetSize(); gpModel.Height = gpModel.FunctionTree.GetHeight(); // the root hasn't changed so we don't need to update // return a CompositeOperation that randomly initializes all nodes of the new subtree return Util.CreateInitializationOperation(TreeGardener.GetAllSubTrees(newTree), scope); } } } }