Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs @ 16189

Last change on this file since 16189 was 16137, checked in by abeham, 6 years ago

#2457:

  • Restructured FLA plugin (moved files between folders, added common base classes)
  • Fixed AC1 in QAPDirectedWalk (ouch!)
  • Changed PartialInformationContent to be in range [0;1]
  • Added unit test for information analysis
  • Refactored information analysis and discard ability to use more symbols than 2 as shapes
File size: 10.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25
26namespace HeuristicLab.Analysis.FitnessLandscape {
27
28  public class InformationAnalysis {
29
30    public class Peak {
31      public double QualityDelta { get; private set; }
32      public double Value { get; private set; }
33      public Peak(double qualityDelta, double value) {
34        QualityDelta = qualityDelta;
35        Value = value;
36      }
37    }
38
39    public List<double> InformationContent { get; private set; }
40    public List<double> SymmetricInformationContent { get; private set; }
41    public List<double> PartialInformationContent { get; private set; }
42    public List<double> DensityBasinInformation { get; private set; }
43    public List<double> SymmetricDensityBasinInformation { get; private set; }
44    public List<double> TotalEntropy { get; private set; }
45    public List<double> SymmetricTotalEntropy { get; private set; }
46    public List<double> QualityDelta { get; private set; }
47    public double InformationStability { get; private set; }
48    public int Regularity { get; private set; }
49    public int Diversity { get; private set; }
50    public Peak PeakInformationContent { get; private set; }
51    public Peak PeakSymmetricInformationContent { get; private set; }
52    public Peak PeakDensityBasinInformation { get; private set; }
53    public Peak PeakSymmetricDensityBasinInformation { get; private set; }
54    public Peak PeakTotalEntropy { get; private set; }
55    public Peak PeakSymmetricTotalEntropy { get; private set; }
56
57    public InformationAnalysis(IList<double> qualities, int nQuantiles = 20) {
58      InformationContent = new List<double>(nQuantiles);
59      SymmetricInformationContent = new List<double>(nQuantiles);
60      PartialInformationContent = new List<double>(nQuantiles);
61      DensityBasinInformation = new List<double>(nQuantiles);
62      SymmetricDensityBasinInformation = new List<double>(nQuantiles);
63      TotalEntropy = new List<double>(nQuantiles);
64      SymmetricTotalEntropy = new List<double>(nQuantiles);
65      QualityDelta = new List<double>(nQuantiles);
66      if (qualities.Count > 1)
67        PerformAnalysis(qualities, nQuantiles);
68    }
69
70    private void PerformAnalysis(IList<double> qualities, int nQuantiles) {
71      var differences = Differences(qualities).ToList();
72      InformationStability = differences.Select(Math.Abs).Max();
73      Regularity = new HashSet<double>(differences).Count;
74      Diversity = new HashSet<double>(qualities).Count;
75      var absDifferences = differences.Select(Math.Abs).OrderBy(d => d).ToList();
76      nQuantiles = Math.Min(nQuantiles, absDifferences.Count);
77      var thresholds = (nQuantiles == 0
78                         ? absDifferences
79                         : UniqueThresholdCalculator.DetermineThresholds(differences, nQuantiles)).ToList();
80      foreach (var eps in thresholds) {
81        if (QualityDelta.Count > 0 && QualityDelta.Last() == eps) {
82          QualityDelta.DuplicateLast();
83          InformationContent.DuplicateLast();
84          DensityBasinInformation.DuplicateLast();
85          TotalEntropy.DuplicateLast();
86          PartialInformationContent.DuplicateLast();
87        } else {
88          var slopes = ToSlopes(eps, differences).ToList();
89          var shapes = ToShapes(slopes).ToList();
90          var symmetricShapes = shapes.Select(x => Shape.GetSymmetric(x)).ToList();
91
92          var shapeFreqs = GetFrequencies(shapes);
93          var symShapeFreqs = GetFrequencies(symmetricShapes);
94
95          foreach (var symShape in Shape.Symmetric.Where(x => x.Sum > 0)) {
96            if (symShapeFreqs.TryGetValue(symShape, out var freq)) {
97              symShapeFreqs[symShape] = freq / 2;
98            }
99          }
100          QualityDelta.Add(eps);
101
102          InformationContent.Add(CalculateEntropy(shapeFreqs, Shape.NonUniform.ToList(), shapes.Count));
103          SymmetricInformationContent.Add(CalculateEntropy(symShapeFreqs, Shape.SymmetricNonUniform.ToList(), symmetricShapes.Count));
104
105          DensityBasinInformation.Add(CalculateEntropy(shapeFreqs, Shape.Uniform.ToList(), shapes.Count));
106          SymmetricDensityBasinInformation.Add(CalculateEntropy(symShapeFreqs, Shape.SymmetricUniform.ToList(), symmetricShapes.Count));
107
108          TotalEntropy.Add(CalculateEntropy(shapeFreqs, Shape.All.ToList(), shapes.Count));
109          SymmetricTotalEntropy.Add(CalculateEntropy(symShapeFreqs, Shape.Symmetric.ToList(), symmetricShapes.Count));
110
111          PartialInformationContent.Add(CalculatePartialInformationContent(eps, differences));
112        }
113      }
114      PeakInformationContent = GetPeak(QualityDelta, InformationContent);
115      PeakSymmetricInformationContent = GetPeak(QualityDelta, SymmetricInformationContent);
116      PeakDensityBasinInformation = GetPeak(QualityDelta, DensityBasinInformation);
117      PeakSymmetricDensityBasinInformation = GetPeak(QualityDelta, SymmetricDensityBasinInformation);
118      PeakTotalEntropy = GetPeak(QualityDelta, TotalEntropy);
119      PeakSymmetricTotalEntropy = GetPeak(QualityDelta, SymmetricTotalEntropy);
120    }
121
122    public static Peak GetPeak(IEnumerable<double> indexes, IEnumerable<double> values) {
123      var max = indexes.Zip(values, (i, v) => new { i, v }).OrderByDescending(p => p.v).First();
124      return new Peak(max.i, max.v);
125    }
126
127    public enum Slope {
128      Up = 1,
129      Flat = 0,
130      Down = -1
131    }
132
133    public class Shape {
134      private static readonly Shape[] s = new Shape[] {
135        new Shape() { First = Slope.Down, Second = Slope.Down }, // 0
136        new Shape() { First = Slope.Down, Second = Slope.Flat }, // 1
137        new Shape() { First = Slope.Down, Second = Slope.Up   }, // 2
138        new Shape() { First = Slope.Flat, Second = Slope.Down }, // 3
139        new Shape() { First = Slope.Flat, Second = Slope.Flat }, // 4
140        new Shape() { First = Slope.Flat, Second = Slope.Up   }, // 5
141        new Shape() { First = Slope.Up,   Second = Slope.Down }, // 6
142        new Shape() { First = Slope.Up,   Second = Slope.Flat }, // 7
143        new Shape() { First = Slope.Up,   Second = Slope.Up   }, // 8
144      };
145      public static IEnumerable<Shape> All { get { return s; } }
146      public static IEnumerable<Shape> Uniform { get { return All.Where(x => x.First == x.Second); } }
147      public static IEnumerable<Shape> NonUniform { get { return All.Where(x => x.First != x.Second); } }
148      public static IEnumerable<Shape> Symmetric { get { return All.Where(x => x.Sum >= 0); } }
149      public static IEnumerable<Shape> SymmetricUniform { get { return Uniform.Where(x => x.First != Slope.Down); } }
150      public static IEnumerable<Shape> SymmetricNonUniform { get { return NonUniform.Where(x => x.Sum >= 0); } }
151
152      public Slope First { get; private set; }
153      public Slope Second { get; private set; }
154
155      internal int Sum { get { return (int)First + (int)Second; } }
156
157      public IEnumerable<Slope> Slopes {
158        get {
159          yield return First;
160          yield return Second;
161        }
162      }
163
164      private Shape() {
165
166      }
167
168      public static Shape Get(Slope first, Slope second) {
169        var a = 1 + (int)first; var b = 1 + (int)second;
170        return s[a * 3 + b];
171      }
172
173      public static Shape GetSymmetric(Shape shape) {
174        if (shape.Sum >= 0) return shape;
175        if (shape.Sum == -2) return s[8]; // both are Slope.Down
176        if (shape.First == Slope.Down) return s[5];
177        return s[7]; // shape.Second == Slope.Down
178      }
179
180      public override string ToString() {
181        return string.Join("", Slopes.Select(s => (s == Slope.Down ? "\\" : (s == Slope.Up ? "/" : "-"))));
182      }
183    }
184
185   
186
187    private static IEnumerable<Slope> ToSlopes(double eps, IEnumerable<double> differences) {
188      return differences.Select(d => (d > eps ? Slope.Up : (d < -eps ? Slope.Down : Slope.Flat)));
189    }
190
191    private static IEnumerable<Shape> ToShapes(IEnumerable<Slope> slopes) {
192      var iter = slopes.GetEnumerator();
193      if (!iter.MoveNext()) yield break;
194      var prev = iter.Current;
195      while (iter.MoveNext()) {
196        var cur = iter.Current;
197        yield return Shape.Get(prev, cur);
198        prev = cur;
199      }
200    }
201
202    private static double CalculateEntropy(Dictionary<Shape, int> shapeCounts, ICollection<Shape> shapeTypes, int totalShapes) {
203      return shapeTypes.Where(x => shapeCounts.ContainsKey(x))
204        .Aggregate(0.0, (current, s) => current - Entropy(shapeCounts[s], totalShapes, shapeTypes.Count));
205    }
206
207    private static double CalculatePartialInformationContent(double eps, ICollection<double> differences) {
208      var iter = differences.GetEnumerator();
209      if (!iter.MoveNext()) return 0;
210
211      var slope = iter.Current < -eps ? -1 : (iter.Current > eps ? 1 : 0);
212      var nPeaks = Math.Abs(slope);
213      var count = 1;
214      while (iter.MoveNext()) {
215        var d = iter.Current;
216        if (d > eps) {
217          if (slope < 0) nPeaks++;
218          slope = +1;
219        } else if (d < -eps) {
220          if (slope > 0) nPeaks++;
221          slope = -1;
222        }
223        count++;
224      }
225      return nPeaks / (double)count;
226    }
227
228    private static Dictionary<Shape, int> GetFrequencies(IEnumerable<Shape> shapes) {
229      return shapes.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
230    }
231
232    private static double Entropy(int count, int total, int nCases) {
233      if (count == 0) return 0;
234      var freq = 1.0 * count / total;
235      return freq * Math.Log(freq, nCases);
236    }
237
238    private static IEnumerable<double> Differences(IEnumerable<double> values) {
239      return values.Delta((x, y) => y - x);
240    }
241
242  }
243}
Note: See TracBrowser for help on using the repository browser.