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;
}
}
}