using HeuristicLab.BioBoost.ProblemDescription; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; using System; using System.Linq; namespace HeuristicLab.BioBoost.Operators.Mutation { [StorableClass] public class TargetMergingIntegerVectorManipulator : BoundedIntegerVectorManipulator { #region Parameters public LookupParameter DistanceMatrixParameter { get { return (LookupParameter) Parameters["DistanceMatrix"]; } } public ValueParameter DistanceMatrixInProblemDataParameter { get { return (ValueParameter) Parameters["DistanceMatrixInProblemData"]; } } public ILookupParameter ProblemDataParameter { get { return (ILookupParameter) Parameters["ProblemData"]; } } public ValueLookupParameter AvgBundleMutationRatioParameter { get { return (ValueLookupParameter) Parameters["AvgBundleMutationRatio"]; } } #endregion #region Parameter Values public DistanceMatrix DistanceMatrix { get { if (DistanceMatrixInProblemData) { return ((IValueParameter) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value; } else { return DistanceMatrixParameter.ActualValue; } } } public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } } public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } } public double AvgBundleMutationRatio { get { return AvgBundleMutationRatioParameter.ActualValue.Value; } } #endregion #region Construction & Cloning [StorableConstructor] protected TargetMergingIntegerVectorManipulator(bool isDeserializing) : base(isDeserializing) {} protected TargetMergingIntegerVectorManipulator(TargetMergingIntegerVectorManipulator orig, Cloner cloner) : base(orig, cloner) {} public TargetMergingIntegerVectorManipulator() { Parameters.Add(new LookupParameter("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); Parameters.Add(new ValueParameter("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true))); Parameters.Add(new LookupParameter("ProblemData", "The problem instance description container.")); Parameters.Add(new ValueLookupParameter("AvgBundleMutationRatio", "The average ratio of modified targets in a bundle.", new PercentValue(1))); } public override IDeepCloneable Clone(Cloner cloner) { return new TargetMergingIntegerVectorManipulator(this, cloner); } #endregion protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) { var ratio = new NormalDistributedRandom(random, Math.Min(1, Math.Max(0, AvgBundleMutationRatio)), 0.5).NextDouble(); var targetGroups = integerVector .Select((t, i) => new {t, i}) .GroupBy(x => x.t, x => x.i) .Shuffle(random) .Take(2) .ToList(); if (targetGroups.Count == 2) { var dm = DistanceMatrix; var key1 = targetGroups[0].Key; var key2 = targetGroups[1].Key; var targetList1 = targetGroups[0].Shuffle(random).ToList(); var targetList2 = targetGroups[1].Shuffle(random).ToList(); var center = Enumerable .Range(0, integerVector.Length) .Select(i => new {idx = i, dist = dm[key1, i] + dm[key2, i]}) .MinItems(d => d.dist) .Shuffle(random) .First(); foreach (var i in targetList1.Take(Math.Max(1, (int)Math.Round(ratio*targetList1.Count)))) { integerVector[i] = center.idx; } foreach (var i in targetList2.Take(Math.Max(1, (int)Math.Round(ratio*targetList2.Count)))) { integerVector[i] = center.idx; } } else if (targetGroups.Count == 1) { integerVector[random.Next(integerVector.Length)] = random.Next(integerVector.Length); } } } }