using System; using System.Collections.Generic; using System.Linq; namespace HeuristicLab.Analysis.FitnessLandscape.Analysis { public class InformationAnalysis { public class Peak { public double QualityDelta { get; private set; } public double Value { get; private set; } public Peak(double qualityDelta, double value) { QualityDelta = qualityDelta; Value = value; } } public List InformationContent { get; private set; } public List PartialInformationContent { get; private set; } public List DensityBasinInformation { get; private set; } public List QualityDelta { get; private set; } public double InformationStability { get; private set; } public int Regularity { get; private set; } public Peak PeakInformationContent { get; private set; } public Peak PeakPartialInformationContent { get; private set; } public Peak PeakDensityBasinInformation { get; private set; } public InformationAnalysis(IEnumerable qualities, int nQuantiles) { InformationContent = new List(); PartialInformationContent = new List(); DensityBasinInformation = new List(); QualityDelta = new List(); PerformAnalysis(qualities, nQuantiles); } private void PerformAnalysis(IEnumerable qualities, int nQuantiles) { var differences = Differences(qualities).ToList(); InformationStability = differences.Select(d => Math.Abs(d)).Max(); Regularity = new HashSet(differences).Count; var thresholds = UniqueThresholdCalculator.DetermineThresholds(differences, nQuantiles).ToList(); foreach (var eps in thresholds) { var shapes = Shapes(eps, differences).ToList(); int[] shape_counts = CountShapes(shapes); QualityDelta.Add(eps); InformationContent.Add(CalculateInformationContent(shape_counts, shapes.Count)); PartialInformationContent.Add(CalculatePartialInformationContent(eps, differences)); DensityBasinInformation.Add(CalculateDensityBasinInformation(shape_counts, shapes.Count)); } PeakDensityBasinInformation = GetPeak(QualityDelta, InformationContent); PeakPartialInformationContent = GetPeak(QualityDelta, PartialInformationContent); PeakDensityBasinInformation = GetPeak(QualityDelta, DensityBasinInformation); } public static Peak GetPeak(IEnumerable indexes, IEnumerable values) { var max = indexes.Zip(values, (i, v) => new { i, v }).OrderByDescending(p => p.v).First(); return new Peak(max.i, max.v); } public enum Shape { DecDec = -4, EquDec = -3, IncDec = -2, DecEqu = -1, EquEqu = 0, IncEqu = 1, DecInc = 2, EquInc = 3, IncInc = 4 } private static IEnumerable Shapes(double eps, IEnumerable differences) { return Utils.Delta(differences, (x, y) => (Shape) ((x >= eps ? 1 : (x <= -eps ? -1 : 0)) + (y >= eps ? 3 : (y <= -eps ? -3 : 0)))); } private static double CalculateInformationContent(int[] shape_counts, int total_n_shapes) { return -Entropy(shape_counts[(int)Shape.EquDec + 4], total_n_shapes, 6) - Entropy(shape_counts[(int)Shape.IncDec + 4], total_n_shapes, 6) - Entropy(shape_counts[(int)Shape.DecEqu + 4], total_n_shapes, 6) - Entropy(shape_counts[(int)Shape.IncEqu + 4], total_n_shapes, 6) - Entropy(shape_counts[(int)Shape.DecInc + 4], total_n_shapes, 6) - Entropy(shape_counts[(int)Shape.EquInc + 4], total_n_shapes, 6); } private static double CalculateDensityBasinInformation(int[] shape_counts, int total_n_shapes) { return -Entropy(shape_counts[(int)Shape.DecDec + 4], total_n_shapes, 3) - Entropy(shape_counts[(int)Shape.EquEqu + 4], total_n_shapes, 3) - Entropy(shape_counts[(int)Shape.IncInc + 4], total_n_shapes, 3); } private static double CalculatePartialInformationContent(double eps, List differences) { int slope = 0; int nPeaks = 0; foreach (var d in differences) { if (d >= eps) { if (slope < 0) nPeaks++; slope = +1; } else if (d <= -eps) { if (slope > 0) nPeaks++; slope = -1; } } return 1.0 * nPeaks / differences.Count; } private static int[] CountShapes(IEnumerable shapes) { int[] shape_counts = new int[9]; foreach (var s in shapes) { shape_counts[(int)s + 4]++; } return shape_counts; } private static double Entropy(int count, int total, int n_cases) { if (count == 0) return 0; double freq = 1.0 * count / total; return freq * Math.Log(freq, n_cases); } private static IEnumerable Differences(IEnumerable values) { return Utils.Delta(values, (x, y) => y - x); } } }