namespace HeuristicLab.Problems.ProgramSynthesis { using System; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; /// /// Alternation crossover for plush vectors. /// [Item("AlternationCrossover", "Alternation crossover for plush vectors.")] [StorableClass] public class AlternationCrossover : InstrumentedOperator, IPlushCrossover, IStochasticOperator { private const double Mean = 0.0; public AlternationCrossover() { Parameters.Add(new LookupParameter("Random", "The pseudo random number generator which should be used for stochastic crossover operators.")); Parameters.Add(new ScopeTreeLookupParameter("Parents", "The parent vectors which should be crossed.")); ParentsParameter.ActualName = "PlushVector"; Parameters.Add(new LookupParameter("Child", "The child vector resulting from the crossover.")); ChildParameter.ActualName = "PlushVector"; Parameters.Add(new LookupParameter("MaxProgramLength", "The max length of children")); Parameters.Add(new FixedValueParameter("AlternationRate", "Specifies the probability of switching to another parent.", new PercentValue(0.5))); Parameters.Add(new FixedValueParameter("AlignmentDeviation", "When alternating between parents, the index at which to continue copying may be offset backward or forward some amount based on a random sample from a normal distribution with mean 0 and standard deviation set by the alignment deviation parameter", new DoubleValue(1.0))); } [StorableConstructor] public AlternationCrossover(bool deserializing) : base(deserializing) { } public AlternationCrossover(AlternationCrossover origin, Cloner cloner) : base(origin, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new AlternationCrossover(this, cloner); } public ILookupParameter MaxProgramLengthParameter { get { return (ILookupParameter)Parameters["MaxProgramLength"]; } } public int MaxProgramLength { get { return MaxProgramLengthParameter.ActualValue.Value; } set { MaxProgramLengthParameter.ActualValue.Value = value; } } public IValueParameter AlternationRateParameter { get { return (IValueParameter)Parameters["AlternationRate"]; } } public double AlternationRate { get { return AlternationRateParameter.Value.Value; } set { AlternationRateParameter.Value.Value = value; } } public IValueParameter AlignmentDeviationParameter { get { return (IValueParameter)Parameters["AlignmentDeviation"]; } } public double AlignmentDeviation { get { return AlignmentDeviationParameter.Value.Value; } set { AlignmentDeviationParameter.Value.Value = value; } } public ILookupParameter RandomParameter { get { return (LookupParameter)Parameters["Random"]; } } public ILookupParameter> ParentsParameter { get { return (ScopeTreeLookupParameter)Parameters["Parents"]; } } public ILookupParameter ChildParameter { get { return (ILookupParameter)Parameters["Child"]; } } public sealed override IOperation InstrumentedApply() { ChildParameter.ActualValue = Cross( RandomParameter.ActualValue, ParentsParameter.ActualValue, AlternationRate, MaxProgramLength, AlignmentDeviation); return base.InstrumentedApply(); } private static PlushVector Cross( IRandom random, ItemArray parents, double alternationRate, int maxChildLength, double alignmentDeviation) { var normalDistributedRandom = new NormalDistributedRandom(random, Mean, alignmentDeviation); var maxLength = parents.Max(p => p.Entries.Count); var parentIndex = random.Next(0, 2); var parent = parents[parentIndex]; var child = new PlushVector(maxLength); for (var i = 0; i < maxLength && child.Entries.Count <= maxChildLength; i++) { // if parent is shorter than the other, then ignore those entries if (i < parent.Entries.Count) child.Add(parent[i]); // switch parent? if (random.NextDouble() < alternationRate) { parentIndex = parentIndex == 0 ? 1 : 0; parent = parents[parentIndex]; i += normalDistributedRandom.NextRounded(); i = Math.Max(i, 0); } } return child; } } }