namespace HeuristicLab.Problems.ProgramSynthesis.Push.Crossover {
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.Problems.ProgramSynthesis.Push.Encoding;
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 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)));
Parameters.Add(new FixedValueParameter("MaxLength", "The max length of a children", new IntValue(100)));
}
[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 IValueParameter MaxLengthParameter
{
get { return (IValueParameter)Parameters["MaxLength"]; }
}
public int MaxLength
{
get { return MaxLengthParameter.Value.Value; }
set { MaxLengthParameter.Value.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);
return base.InstrumentedApply();
}
private PlushVector Cross(IRandom random, ItemArray parents) {
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);
var maxChildLength = 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.Next();
i = Math.Max(i, 0);
}
}
return child;
}
}
}