Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Utilities/UniqueThresholdCalculator.cs @ 18183

Last change on this file since 18183 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: 6.3 KB
RevLine 
[16137]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.Diagnostics;
25using System.Linq;
26
27namespace HeuristicLab.Analysis.FitnessLandscape {
28
29  public static class UniqueThresholdCalculator {
30
31    private sealed class IndexRange {
32
33      public int Start, End, N;
34      public readonly bool Merge;
35      private readonly List<IndexRange> receivers, distributors;
36
37      public IndexRange(int start, int end, int n, bool merge) {
38        Start = start;
39        End = end;
40        N = n;
41        Merge = merge;
42        receivers = new List<IndexRange>();
43        distributors = new List<IndexRange>();
44      }
45
46      public void AddReceiver(IndexRange receiver) {
47        if (receiver != null) {
48          receivers.Add(receiver);
49          receiver.distributors.Add(this);
50        }
51      }
52
53      public void Distribute() {
54        int n = N - 1;
55        Debug.Assert(n >= 0);
56        switch (receivers.Count) {
57          case 0: break; // No receivers indexes are lost :-(
58          case 1: receivers[0].N += n; N = 1; break;
59          case 2: receivers[0].N += n / 2; receivers[1].N += n - n / 2; N = 1; break;
60          default: throw new InvalidOperationException("More than two receivers registered");
61        }
62        var followers = distributors.Where(d => d.Start > End).ToList();
63        if (followers.Count > 0)
64          End = followers.Min(g => g.Start);
65        var predecessors = distributors.Where(d => d.End < Start).ToList();
66        if (predecessors.Count > 0)
67          Start = predecessors.Max(g => g.End);
68      }
69
70      public override string ToString() {
71        return string.Format("[{0}-{1}, n={2}, {3}]", Start, End, N, Merge ? "Merge" : "Spread");
72      }
73    }
74
75    public static IEnumerable<double> DetermineThresholds(IEnumerable<double> differences, int n) {
76      var thresholds = differences.Select(d => Math.Abs(d)).ToList();
77      thresholds.Sort();
78      if (thresholds.Count <= n) {
79        foreach (var t in thresholds)
80          yield return t;
81      } else {
82        double min = thresholds[0];
83        double max = thresholds[thresholds.Count - 1];
84        if (min == max) {
85          yield return min;
86        } else {
87          yield return min;
88          foreach (var t in DetermineInnerThresholds(thresholds, n - 2))
89            yield return t;
90          yield return max;
91        }
92      }
93    }
94
95    private static IEnumerable<double> DetermineInnerThresholds(List<double> thresholds, int n) {
96      n = Math.Min(thresholds.Count - 2, n);
97      var indexes = Enumerable.Range(0, n + 2).Select(i => (int)Math.Round(1.0 * i * (thresholds.Count - 1) / (n + 1))).ToList();
98      var ranges = CreateRanges(thresholds, indexes);
99      RedistributeIndexes(ranges);
100      TrimBoundaryRanges(ranges);
101      if (ranges.Count == 1 && ranges[0].Start == 0 && ranges[0].End == thresholds.Count - 1 && ranges[0].N == n) {
102        if (ranges[0].Merge)
103          yield return thresholds[ranges[0].Start];
104        else
105          foreach (var i in indexes.Where(i => ranges[0].Start < i && i < ranges[0].End))
106            yield return thresholds[i];
107      } else {
108        foreach (var range in ranges) {
109          if (range.Merge)
110            yield return thresholds[range.Start];
111          else
112            foreach (var t in DetermineInnerThresholds(thresholds.GetRange(range.Start, range.End - range.Start + 1), range.N))
113              yield return t;
114        }
115      }
116    }
117
118    private static void TrimBoundaryRanges(List<IndexRange> ranges) {
119      if (ranges.Count > 0)
120        if (ranges[0].Merge)
121          ranges.RemoveAt(0);
122        else
123          ranges[0].N--;
124      if (ranges.Count > 0)
125        if (ranges[ranges.Count - 1].Merge)
126          ranges.RemoveAt(ranges.Count - 1);
127        else
128          ranges[ranges.Count - 1].N--;
129    }
130
131    private static void RedistributeIndexes(List<IndexRange> ranges) {
132      IndexRange lastReceiver = null;
133      List<IndexRange> lastDistributors = new List<IndexRange>();
134      foreach (var range in ranges) {
135        if (range.Merge) {
136          range.AddReceiver(lastReceiver);
137          lastDistributors.Add(range);
138        } else {
139          foreach (var d in lastDistributors)
140            d.AddReceiver(range);
141          lastDistributors = new List<IndexRange>();
142          lastReceiver = range;
143        }
144      }
145      foreach (var range in ranges) {
146        range.Distribute();
147      }
148    }
149
150    private static List<IndexRange> CreateRanges(List<double> thresholds, List<int> indexes) {
151      var values = indexes.Select(i => new { i, v = thresholds[i] }).ToList();
152      var mergedRanges = values.GroupBy(iv => iv.v)
153        .Select(g => g.Count() == 1 ?
154          new IndexRange(g.First().i, g.First().i, 1, false) :
155          new IndexRange(g.Min(iv => iv.i), g.Max(iv => iv.i), g.Count(), true)).ToList();
156      IndexRange lastSpreadRange = null;
157      var ranges = new List<IndexRange>();
158      foreach (var group in mergedRanges) {
159        if (group.Merge) {
160          if (lastSpreadRange != null) {
161            ranges.Add(lastSpreadRange);
162            lastSpreadRange = null;
163          }
164          ranges.Add(group);
165        } else {
166          if (lastSpreadRange != null) {
167            lastSpreadRange.End = group.End;
168            lastSpreadRange.N++;
169          } else {
170            lastSpreadRange = group;
171          }
172        }
173      }
174      if (lastSpreadRange != null)
175        ranges.Add(lastSpreadRange);
176      return ranges;
177    }
178  }
179}
Note: See TracBrowser for help on using the repository browser.