using System;
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
namespace HeuristicLab.Problems.Robocode
{
///
/// Takes two parent individuals P0 and P1 each. Selects a random node N0 of P0 and a random node N1 of P1.
/// And replaces the branch with root0 N0 in P0 with N1 from P1 if the tree-size limits are not violated.
/// When recombination with N0 and N1 would create a tree that is too large or invalid the operator randomly selects new N0 and N1
/// until a valid configuration is found.
///
[Item("RobocodeMethodCrossover", "An operator which performs crossover of randomly chosen statements with a method.")]
[StorableClass]
public class RobocodeMethodCrossover : SymbolicExpressionTreeCrossover//, ISymbolicExpressionTreeSizeConstraintOperator
{
#region Parameter Names
private const string HomologousCrossoverPrameterName = "HomologousCrossover";
private const string MaximumCrossoverMethodsParameterName = "MaximumCrossoverMethods";
#endregion
#region Parameter Properties
public IValueLookupParameter HomologousCrossoverParameter
{
get { return (IValueLookupParameter)Parameters[HomologousCrossoverPrameterName]; }
}
public IValueLookupParameter MaximumCrossoverMethodsParameter
{
get { return (IValueLookupParameter)Parameters[MaximumCrossoverMethodsParameterName]; }
}
#endregion
#region Properties
public BoolValue HomologousCrossover
{
get { return HomologousCrossoverParameter.ActualValue; }
}
public IntValue MaximumCrossoverMethods
{
get { return MaximumCrossoverMethodsParameter.ActualValue; }
}
#endregion
[StorableConstructor]
protected RobocodeMethodCrossover(bool deserializing) : base(deserializing) { }
protected RobocodeMethodCrossover(RobocodeMethodCrossover original, Cloner cloner) :
base(original, cloner) { }
public RobocodeMethodCrossover()
: base()
{
Parameters.Add(new ValueLookupParameter(HomologousCrossoverPrameterName,
"Specifies if the number of statements exchanged between the two parents is the same.", new BoolValue(false)));
Parameters.Add(new ValueLookupParameter(MaximumCrossoverMethodsParameterName,
"The maximal methods to apply crossover on (0 or a number higher than the count of " +
"methods means applying crossover to them all).", new IntValue(0)));
}
public override IDeepCloneable Clone(Cloner cloner)
{
return new RobocodeMethodCrossover(this, cloner);
}
public override ISymbolicExpressionTree Crossover(IRandom random,
ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1)
{
return Cross(random, parent0, parent1, HomologousCrossover.Value,
MaximumCrossoverMethods.Value);
}
public static ISymbolicExpressionTree Cross(IRandom random,
ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1,
bool homologous, int maximumCrossoverMethods)
{
// select a random crossover point in the first parent
List crossoverPoints0;
SelectCrossoverPoint(random, parent0, maximumCrossoverMethods, out crossoverPoints0);
foreach (CutPoint c in crossoverPoints0)
{
List allowedBranches = new List();
parent1.Root.ForEachNodePostfix((n) =>
{
if (n.Symbol.GetType() == c.Child.Symbol.GetType())
allowedBranches.Add(n);
});
if (allowedBranches.Count == 0)
{
break;
}
else
{
ISymbolicExpressionTreeNode branch = allowedBranches.FirstOrDefault();
int startBranchParent0 = (c.Child.SubtreeCount <= 2)? 0 : random.Next(0, c.Child.SubtreeCount - 2);
int endBranchParent0 = (c.Child.SubtreeCount <= 2) ? 1 : random.Next(startBranchParent0 + 1, c.Child.SubtreeCount - 1);
int Parent0Branches = endBranchParent0 - startBranchParent0;
for (int i = 0; i < Parent0Branches; i++)
{
c.Child.RemoveSubtree(startBranchParent0);
}
if (homologous)
{
for (int j = startBranchParent0; j <= endBranchParent0; j++)
{
c.Child.AddSubtree(branch.GetSubtree(j));
}
}
else
{
int startBranchParent1 = (branch.SubtreeCount <= 2) ? 0 : random.Next(0, branch.SubtreeCount - 2);
int endBranchParent1 = (branch.SubtreeCount <= 2) ? 1 : random.Next(startBranchParent1 + 1, branch.SubtreeCount - 1);
int Parent1Branches = endBranchParent1 - startBranchParent1;
for (int j = startBranchParent1; j <= endBranchParent1 && c.Child.SubtreeCount < c.Child.Symbol.MaximumArity; j++)
{
c.Child.AddSubtree(branch.GetSubtree(j));
}
}
}
}
return parent0;
}
private static void SelectCrossoverPoint(IRandom random, ISymbolicExpressionTree parent0,
int maximumCrossoverMethods, out List crossoverPoints)
{
List MethodPoints = new List();
parent0.Root.ForEachNodePostfix((n) =>
{
if (n.SubtreeCount > 0 && n != parent0.Root)
{
foreach (var child in n.Subtrees)
{
if (child.Symbol is Run ||
child.Symbol is OnBulletHit ||
child.Symbol is OnBulletMissed ||
child.Symbol is OnHitByBullet ||
child.Symbol is OnHitRobot ||
child.Symbol is OnHitWall ||
child.Symbol is OnScannedRobot)
MethodPoints.Add(new CutPoint(n, child));
}
}
});
if (maximumCrossoverMethods == 0)
crossoverPoints = MethodPoints;
else
{
crossoverPoints = new List();
for (int i = 0; i < maximumCrossoverMethods; i++)
{
CutPoint c = MethodPoints.SelectRandom(random);
crossoverPoints.Add(c);
MethodPoints.Remove(c);
if (MethodPoints.Count == 0) break;
}
}
}
/*private static ISymbolicExpressionTreeNode SelectRandomBranch(IRandom random, IEnumerable branches, double internalNodeProbability)
{
if (internalNodeProbability < 0.0 || internalNodeProbability > 1.0) throw new ArgumentException("internalNodeProbability");
List allowedInternalBranches;
List allowedLeafBranches;
if (random.NextDouble() < internalNodeProbability)
{
// select internal node if possible
allowedInternalBranches = (from branch in branches
where branch != null && branch.SubtreeCount > 0
select branch).ToList();
if (allowedInternalBranches.Count > 0)
{
return allowedInternalBranches.SelectRandom(random);
}
else
{
// no internal nodes allowed => select leaf nodes
allowedLeafBranches = (from branch in branches
where branch == null || branch.SubtreeCount == 0
select branch).ToList();
return allowedLeafBranches.SelectRandom(random);
}
}
else
{
// select leaf node if possible
allowedLeafBranches = (from branch in branches
where branch == null || branch.SubtreeCount == 0
select branch).ToList();
if (allowedLeafBranches.Count > 0)
{
return allowedLeafBranches.SelectRandom(random);
}
else
{
allowedInternalBranches = (from branch in branches
where branch != null && branch.SubtreeCount > 0
select branch).ToList();
return allowedInternalBranches.SelectRandom(random);
}
}
}*/
}
}