#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
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);
}
}
}
}