#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 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 HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
///
/// A base class for operators that manipulate real-valued vectors.
///
[Item("TracingSymbolicExpressionTreeManipulator", "A base class for operators that manipulate symbolic expression trees.")]
[StorableClass]
public abstract class TracingSymbolicExpressionTreeManipulator : TracingSymbolicExpressionTreeOperator, ISymbolicExpressionTreeManipulator {
private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree";
[Storable]
private readonly Dictionary manipulationTypes = new Dictionary();
#region Parameter Properties
public ILookupParameter SymbolicExpressionTreeParameter {
get { return (ILookupParameter)Parameters[SymbolicExpressionTreeParameterName]; }
}
#endregion
#region Properties
public ISymbolicExpressionTree SymbolicExpressionTree {
get { return SymbolicExpressionTreeParameter.ActualValue; }
}
#endregion
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
}
[StorableConstructor]
protected TracingSymbolicExpressionTreeManipulator(bool deserializing) : base(deserializing) { }
protected TracingSymbolicExpressionTreeManipulator(TracingSymbolicExpressionTreeManipulator original, Cloner cloner)
: base(original, cloner) {
this.manipulationTypes = new Dictionary(original.manipulationTypes);
}
public TracingSymbolicExpressionTreeManipulator()
: base() {
Parameters.Add(new LookupParameter(SymbolicExpressionTreeParameterName, "The symbolic expression tree on which the operator should be applied."));
manipulationTypes.Add(typeof(FullTreeShaker), ManipulationType.FullTreeShaker);
manipulationTypes.Add(typeof(OnePointShaker), ManipulationType.OnePointShaker);
manipulationTypes.Add(typeof(ChangeNodeTypeManipulation), ManipulationType.ChangeNodeTypeManipulation);
manipulationTypes.Add(typeof(ReplaceBranchManipulation), ManipulationType.ReplaceBranchManipulation);
manipulationTypes.Add(typeof(RemoveBranchManipulation), ManipulationType.RemoveBranchManipulation);
}
public sealed override IOperation Apply() {
ISymbolicExpressionTree tree = SymbolicExpressionTreeParameter.ActualValue;
AddTracingVariablesToGlobalScope();
/* The following block needs to be explained in more detail;
* If the tree was already affected by crossover (before mutation), then:
* - it will already be contained in the GlobalTraceMap
* - In order to preserve information, a clone of the tree is created
* - The clone represents the intermediate stage of the tree, before mutation is applied
* - The clone therefore represents the child after crossover so GlobalTraceMap[clone] will get tree's parents
* and GlobalFragmentMap[clone] will get the subtree from clone that represents the cloned fragment
* - After tree is mutated, we set GlobalTraceMap[tree] = clone and GlobalFragmentMap[tree] = modified node from tree
*/
Fragment fragment = null;
if (GlobalTraceMap.ContainsKey(tree)) {
var clone = (IItem)tree.Clone();
GlobalCloneMap[clone] = GlobalCloneMap[tree];
GlobalCloneMap[tree] = clone;
GlobalTraceMap[clone] = GlobalTraceMap[tree]; // clone gets parents of tree
GlobalTraceMap[tree] = new ItemList { clone }; // tree gets clone as parent
fragment = (Fragment)GlobalFragmentMap[tree];
int index = tree.IterateNodesBreadth().ToList().IndexOf(fragment.Root); // returns -1 if fragment is not present in tree (can happen if fragment is null)
ISymbolicExpressionTreeNode fragmentRoot = index == -1 ? null : ((ISymbolicExpressionTree)clone).IterateNodesBreadth().ElementAt(index);
GlobalFragmentMap[clone] = new Fragment { Root = fragmentRoot };
} else {
GlobalTraceMap[tree] = new ItemList { GlobalCloneMap[tree] };
}
var clonedTree = (ISymbolicExpressionTree)tree.Clone();
var nodes0 = clonedTree.IterateNodesBreadth().ToList();
Manipulate(RandomParameter.ActualValue, tree);
var nodes1 = tree.IterateNodesBreadth().ToList();
var comparer = SymbolicExpressionTreeNodeComparer;
int min = Math.Min(nodes0.Count, nodes1.Count);
int i = 0; while (i != min && comparer.Equals(nodes0[i], nodes1[i])) ++i;
fragment = new Fragment { Root = i == min ? null : nodes1[i], Index = i };
GlobalFragmentMap[tree] = fragment;
return base.Apply();
}
protected abstract void Manipulate(IRandom random, ISymbolicExpressionTree symbolicExpressionTree);
private struct ManipulationType {
public const byte FullTreeShaker = 1;
public const byte OnePointShaker = 2;
public const byte ChangeNodeTypeManipulation = 3;
public const byte ReplaceBranchManipulation = 4;
public const byte RemoveBranchManipulation = 5;
}
}
}