#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 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 System;
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Encodings.RealVectorEncoding;
using HeuristicLab.Optimization;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Algorithms.MOCMAEvolutionStrategy {
[Item("MinimalDistanceIndicator", "Selection of Offspring based on distance to nearest neighbour")]
[StorableClass]
internal class MinimalDistanceIndicator : Item, IIndicator {
#region Constructor and Cloning
[StorableConstructor]
protected MinimalDistanceIndicator(bool deserializing) : base(deserializing) { }
protected MinimalDistanceIndicator(MinimalDistanceIndicator original, Cloner cloner) : base(original, cloner) { }
public override IDeepCloneable Clone(Cloner cloner) { return new MinimalDistanceIndicator(this, cloner); }
public MinimalDistanceIndicator() { }
#endregion
public int LeastContributer(IReadOnlyList front, MultiObjectiveBasicProblem problem) {
var extracted = front.Select(x => x.PenalizedFitness).ToArray();
if (extracted.Length <= 2) return 0;
var distances = CalcDistances(extracted);
var mindexI = 0;
var mindexJ = 0;
var min = double.MaxValue;
for (var i = 0; i < extracted.Length; i++) {
var d = double.MaxValue;
var minj = 0;
for (var j = 0; j < extracted.Length; j++) {
if (i == j) continue;
var d1 = distances[i, j];
if (!(d1 < d)) continue;
minj = j;
d = d1;
}
if (!(d < min)) continue;
min = d;
mindexI = i;
mindexJ = minj;
}
//break tie with distance to second nearest
var minI = double.MaxValue;
var minJ = double.MaxValue;
for (var i = 0; i < extracted.Length; i++) {
double d;
if (mindexI != i) {
d = distances[mindexI, i];
if (!d.IsAlmost(min)) minI = Math.Min(minI, d);
}
if (mindexJ == i) continue;
d = distances[mindexJ, i];
if (!d.IsAlmost(min)) minJ = Math.Min(minJ, d);
}
//find min
return minI < minJ ? mindexI : mindexJ;
}
#region Helpers
private static double[,] CalcDistances(IReadOnlyList extracted) {
var res = new double[extracted.Count, extracted.Count];
for (var i = 0; i < extracted.Count; i++)
for (var j = 0; j < i; j++)
res[i, j] = res[j, i] = Dist(extracted[i], extracted[j]);
return res;
}
private static double Dist(IEnumerable a, IEnumerable b) {
return Math.Sqrt(a.Zip(b, (x, y) => (x - y) * (x - y)).Sum());
}
#endregion
}
}