Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs @ 14614

Last change on this file since 14614 was 13583, checked in by abeham, 9 years ago

#2457:

  • Added stripped-down version of FLA branch
  • Added appropriate calculators
  • Fixed detecting maximization in RLD view
File size: 9.9 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> PartialInformationContent { get; private set; }
41    public List<double> DensityBasinInformation { get; private set; }
42    public List<double> TotalEntropy { get; private set; }
43    public List<double> QualityDelta { get; private set; }
44    public double InformationStability { get; private set; }
45    public int Regularity { get; private set; }
46    public int Diversity { get; private set; }
47    public Peak PeakInformationContent { get; private set; }
48    public Peak PeakPartialInformationContent { get; private set; }
49    public Peak PeakDensityBasinInformation { get; private set; }
50    public Peak PeakTotalEntropy { get; private set; }
51
52    public InformationAnalysis(IList<double> qualities, int nQuantiles, int shapeSize) {
53      InformationContent = new List<double>();
54      PartialInformationContent = new List<double>();
55      DensityBasinInformation = new List<double>();
56      TotalEntropy = new List<double>();
57      QualityDelta = new List<double>();
58      if (shapeSize < 1)
59        throw new ArgumentException("Shape size must be at least 1 (better 2)");
60      if (qualities.Count > 1)
61        PerformAnalysis(qualities, nQuantiles, shapeSize);
62    }
63
64    private void PerformAnalysis(IList<double> qualities, int nQuantiles, int shapeSize) {
65      var differences = Differences(qualities).ToList();
66      InformationStability = differences.Select(Math.Abs).Max();
67      Regularity = new HashSet<double>(differences).Count;
68      Diversity = new HashSet<double>(qualities).Count;
69      var absDifferences = differences.Select(Math.Abs).OrderBy(d => d).ToList();
70      nQuantiles = Math.Min(nQuantiles, absDifferences.Count);
71      var thresholds = (nQuantiles == 0
72                         ? absDifferences
73                         : UniqueThresholdCalculator.DetermineThresholds(differences, nQuantiles)).ToList();
74      foreach (var eps in thresholds) {
75        if (QualityDelta.Count > 0 && QualityDelta.Last() == eps) {
76          QualityDelta.DuplicateLast();
77          InformationContent.DuplicateLast();
78          DensityBasinInformation.DuplicateLast();
79          TotalEntropy.DuplicateLast();
80          PartialInformationContent.DuplicateLast();
81        } else {
82          var slopes = Slopes(eps, differences).ToList();
83          var shapes = Shapes(shapeSize, slopes).ToList();
84          var shapeCounts = CountShapes(shapes);
85          QualityDelta.Add(eps);
86          InformationContent.Add(CalculateEntropy(Shape.GetAll(shapeSize, Shape.Form.NonUni), shapeCounts, shapes.Count));
87          DensityBasinInformation.Add(CalculateEntropy(Shape.GetAll(shapeSize, Shape.Form.Uni), shapeCounts, shapes.Count));
88          TotalEntropy.Add(CalculateEntropy(Shape.GetAll(shapeSize, Shape.Form.Any), shapeCounts, shapes.Count));
89          PartialInformationContent.Add(CalculatePartialInformationContent(eps, differences));
90        }
91      }
92      PeakInformationContent = GetPeak(QualityDelta, InformationContent);
93      PeakDensityBasinInformation = GetPeak(QualityDelta, DensityBasinInformation);
94      PeakPartialInformationContent = GetPeak(QualityDelta, PartialInformationContent);
95      PeakTotalEntropy = GetPeak(QualityDelta, TotalEntropy);
96    }
97
98    public static Peak GetPeak(IEnumerable<double> indexes, IEnumerable<double> values) {
99      var max = indexes.Zip(values, (i, v) => new { i, v }).OrderByDescending(p => p.v).First();
100      return new Peak(max.i, max.v);
101    }
102
103    public enum Slope {
104      Up = 1,
105      Flat = 0,
106      Down = -1
107    }
108
109    public class Shape : IEnumerable<Slope>, IComparable<Shape> {
110
111      #region types, fields and properties
112      public enum Form { Uni, NonUni, Any }
113
114      private readonly Slope[] slopes;
115
116      private static readonly Dictionary<Tuple<Form, int>, IList<Shape>> SHAPES =
117        new Dictionary<Tuple<Form, int>, IList<Shape>>();
118      #endregion
119
120      public Shape(IEnumerable<Slope> slopes) {
121        this.slopes = slopes.ToArray();
122      }
123
124      #region static methods
125
126      public static Shape Get(params Slope[] slopes) {
127        return new Shape(slopes);
128      }
129
130      public static IList<Shape> GetAll(int size, Form type) {
131        var key = Tuple.Create(type, size);
132        IList<Shape> allShapes;
133        if (!SHAPES.TryGetValue(key, out allShapes)) {
134          allShapes = CreateAll(size, type).ToList();
135          SHAPES[key] = allShapes;
136        }
137        return allShapes;
138      }
139
140      private static IEnumerable<Shape> CreateAll(int size, Form type) {
141        if (size == 0) {
142          yield return Get();
143        } else {
144          foreach (var s in CreateAll(size - 1, type)) {
145            foreach (var s2 in s.ExtendAll(type))
146              yield return s2;
147          }
148        }
149      }
150      #endregion
151
152      private Shape Extend(Slope s) {
153        return new Shape(slopes.Concat(new[] { s }));
154      }
155
156      private IEnumerable<Shape> ExtendAll(Form t) {
157        if (Length == 0 || t == Form.Any) {
158          yield return Extend(Slope.Up);
159          yield return Extend(Slope.Flat);
160          yield return Extend(Slope.Down);
161        } else if (t == Form.Uni) {
162          yield return Extend(slopes[0]);
163        } else if (t == Form.NonUni) {
164          if (slopes.Last() != Slope.Up) yield return Extend(Slope.Up);
165          if (slopes.Last() != Slope.Flat) yield return Extend(Slope.Flat);
166          if (slopes.Last() != Slope.Down) yield return Extend(Slope.Down);
167        }
168      }
169
170      public int Length {
171        get { return slopes.Length; }
172      }
173
174      public Slope this[int i] {
175        get { return slopes[i]; }
176      }
177
178      #region IEnumerable Members
179      public IEnumerator<Slope> GetEnumerator() {
180        return (IEnumerator<Slope>)slopes.GetEnumerator();
181      }
182      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
183        return GetEnumerator();
184      }
185      #endregion
186
187      #region IComparable Members
188
189      public int CompareTo(Shape other) {
190        if (other.Length < Length)
191          return -1;
192        if (other.Length > Length)
193          return 1;
194        for (var i = 0; i < Length; i++) {
195          var d = slopes[i].CompareTo(other.slopes[i]);
196          if (d != 0)
197            return d;
198        }
199        return 0;
200      }
201      public override bool Equals(object obj) {
202        var s = obj as Shape;
203        if (s == null) return false;
204        return CompareTo(s) == 0;
205      }
206      public override int GetHashCode() {
207        return slopes.Aggregate(0, (a, s) => a * 3 + ((int)s + 1)).GetHashCode();
208      }
209
210      #endregion
211
212      private string asString;
213      public override string ToString() {
214        return asString ?? (asString = string.Join("", slopes.Select(s => (s == Slope.Down ? "v" : (s == Slope.Up ? "^" : "-")))));
215      }
216    }
217
218    private static IEnumerable<Slope> Slopes(double eps, IEnumerable<double> differences) {
219      return differences.Select(d => (d > eps ? Slope.Up : (d < -eps ? Slope.Down : 0)));
220    }
221
222    private static IEnumerable<Shape> Shapes(int size, IEnumerable<Slope> slopes) {
223      var q = new Queue<Slope>();
224      foreach (var s in slopes) {
225        q.Enqueue(s);
226        if (q.Count < size) continue;
227        yield return new Shape(q);
228        q.Dequeue();
229      }
230    }
231
232    private static double CalculateEntropy(IList<Shape> shapes, Dictionary<Shape, int> shapeCounts, int totalNShapes) {
233      return shapes.Aggregate(0.0, (current, s) => current - Entropy(shapeCounts.GetValueOrDefault(s, 0), totalNShapes, shapes.Count));
234    }
235
236    private static double CalculatePartialInformationContent(double eps, ICollection<double> differences) {
237      int slope = 0;
238      int nPeaks = 0;
239      foreach (var d in differences) {
240        if (d > eps) {
241          if (slope < 0) nPeaks++;
242          slope = +1;
243        } else if (d < -eps) {
244          if (slope > 0) nPeaks++;
245          slope = -1;
246        }
247      }
248      return 1.0 * nPeaks / differences.Count;
249    }
250
251    private static Dictionary<Shape, int> CountShapes(IEnumerable<Shape> shapes) {
252      var shapeCounts = new Dictionary<Shape, int>();
253      foreach (var group in shapes.GroupBy(s => s))
254        shapeCounts[group.Key] = group.Count();
255      return shapeCounts;
256    }
257
258    private static double Entropy(int count, int total, int nCases) {
259      if (count == 0)
260        return 0;
261      double freq = 1.0 * count / total;
262      return freq * Math.Log(freq, nCases);
263    }
264
265    private static IEnumerable<double> Differences(IEnumerable<double> values) {
266      return values.Delta((x, y) => y - x);
267    }
268
269  }
270}
Note: See TracBrowser for help on using the repository browser.