Free cookie consent management tool by TermsFeed Policy Generator

source: branches/FitnessLandscapeAnalysis/HeuristicLab.Analysis.FitnessLandscape/Analysis/InformationAnalysis.cs @ 8744

Last change on this file since 8744 was 8744, checked in by epitzer, 12 years ago

Improve Information Analyzer #1696

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