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 System; using System.Linq; namespace HeuristicLab.BioBoost.Operators.Mutation { [StorableClass] public class DistanceBasedIntegerVectorMutator : IntegerVectorManipulator { #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 ILookupParameter ViableSourcesParameter { get { return (ILookupParameter) Parameters["ViableSources"]; } } public ILookupParameter ViableTargetsParameter { get { return (ILookupParameter) Parameters["ViableTargets"]; } } public IValueLookupParameter MaximumDistanceParameter { get { return (IValueLookupParameter) Parameters["MaximumDistance"]; } } #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 IntArray ViableSources { get { return ViableSourcesParameter.ActualValue; } } public IntArray ViableTargets { get { return ViableTargetsParameter.ActualValue; } } public double MaximumDistance { get { return MaximumDistanceParameter.ActualValue.Value; } } #endregion #region Construction & Cloning [StorableConstructor] protected DistanceBasedIntegerVectorMutator(bool isDeserializing) : base(isDeserializing) {} protected DistanceBasedIntegerVectorMutator(DistanceBasedIntegerVectorMutator orig, Cloner cloner) : base(orig, cloner) {} public DistanceBasedIntegerVectorMutator() { Parameters.Add(new LookupParameter("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this 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", "Contains fixed values describing the problem.")); Parameters.Add(new LookupParameter("ViableSources", "A list with all indices of viable source regions.")); Parameters.Add(new LookupParameter("ViableTargets", "A list with all indices of viable target regions.")); Parameters.Add(new ValueLookupParameter("MaximumDistance", "the maximum distance from source to target allowed for mutation", new DoubleValue(Double.MaxValue))); } public override IDeepCloneable Clone(Cloner cloner) { return new DistanceBasedIntegerVectorMutator(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey("ViableSources")) Parameters.Add(new LookupParameter("ViableSources", "A list with all indices of viable source regions.")); if (!Parameters.ContainsKey("ViableTargets")) Parameters.Add(new LookupParameter("ViableTargets", "A list with all indices of viable target regions.")); if (!Parameters.ContainsKey("MaximumDistance")) Parameters.Add(new ValueLookupParameter("MaximumDistance", "the maximum distance from source to target allowed for mutation", new DoubleValue(Double.MaxValue))); } #endregion protected override void Manipulate(IRandom random, IntegerVector integerVector) { var sources = ViableSources ?? new IntArray(Enumerable.Range(0, integerVector.Length).ToArray()); var targets = ViableTargets ?? new IntArray(Enumerable.Range(0, integerVector.Length).ToArray()); var source = random.Next(sources.Length); var target = integerVector[sources[source]]; var neighborDistances = new double[0].Select((d, idx) => new {index = idx, distance = d}).ToList(); var distances = DistanceMatrix; var maxDistance = 0d; for (int j = 0; j < targets.Length; j++) { if (distances[source, targets[j]] > MaximumDistance) continue; var dist = distances[target, targets[j]]; neighborDistances.Add(new {index = targets[j], distance = dist}); maxDistance = Math.Max(dist, maxDistance); } neighborDistances = neighborDistances.Select(p => new {p.index, distance = maxDistance - p.distance}).ToList(); neighborDistances.Sort((a, b) => b.distance.CompareTo(a.distance)); var totalDistance = neighborDistances.Sum(p => p.distance); var threshold = random.NextDouble()*totalDistance; var sum = 0d; var index = 0; while (index < neighborDistances.Count && sum < threshold) { sum += neighborDistances[index].distance; index++; } if (index < 0 || index >= neighborDistances.Count) { integerVector[sources[source]] = sources[source]; // reset to local transport if no choices exist } else { integerVector[sources[source]] = neighborDistances[index].index; } } } }