Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Mutators/SegmentOptimization/SamplingSegmentOptimizationManipulator.cs @ 18227

Last change on this file since 18227 was 18227, checked in by pfleck, 2 years ago

#3040 Added cached option version of sampling mutator.

File size: 14.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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;
25using HEAL.Attic;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Encodings.IntegerVectorEncoding;
30using HeuristicLab.Parameters;
31using HeuristicLab.Random;
32
33namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
34  [Item("SamplingSegmentOptimizationManipulator", "")]
35  [StorableType("4D4D8BC9-2C2B-418E-B9AE-5FB5511C70CE")]
36  public class SamplingSegmentOptimizationManipulator : SegmentOptimizationMutator {
37
38    [StorableType("65B2E870-7EED-4DD0-918E-94A346671784")]
39    public enum DimensionType {
40      All,
41      Single
42    }
43    [StorableType("C73064F2-4E2F-473F-8DBA-DD47881726D4")]
44    public enum SearchRangeType {
45      None, // Fixed on current value
46      Full,
47      RandomDirection,
48      RandomRange,
49      DirectedDirection,
50      DirectedRange
51    }
52    [StorableType("A9EBE01E-53DE-4EB7-94B3-26C624034A08")]
53    public enum SamplingType {
54      Exhaustive,
55      RandomSampling,
56      LinearSelection // "generalized nth"
57    }
58
59    [StorableType("4EBF0DFE-90A1-4DFE-8CC7-D358EF8AF96B")]
60    [Flags]
61    public enum SamplingPointsType {
62      None = 0,
63      BeforeCombinations = 1,
64      AfterCombinations = 2
65    }
66
67    #region Properties
68    public DimensionType Dimension { get { return DimensionParameter.Value.Value; } set { DimensionParameter.Value.Value = value; } }
69    public SearchRangeType SearchRange { get { return SearchRangeParameter.Value.Value; } set { SearchRangeParameter.Value.Value = value; } }
70    public double DirectedRangeStepSize { get { return DirectedRangeStepSizeParameter.Value.Value; } set { DirectedRangeStepSizeParameter.Value.Value = value; } }
71    public int DirectedRangeRange { get { return DirectedRangeRangeParameter.Value.Value; } set { DirectedRangeRangeParameter.Value.Value = value; } }
72    public SamplingType Sampling { get { return SamplingParameter.Value.Value; } set { SamplingParameter.Value.Value = value; } }
73    public int SampleCount { get { return SampleCountParameter.Value.Value; } set { SampleCountParameter.Value.Value = value; } }
74    public SamplingPointsType SamplingPoints { get { return SamplingPointsParameter.Value.Value; } set { SamplingPointsParameter.Value.Value = value; } }
75    #endregion
76
77    #region Parameter Properties
78    public ValueParameter<EnumValue<DimensionType>> DimensionParameter => (ValueParameter<EnumValue<DimensionType>>)Parameters["Dimension"];
79    public ValueParameter<EnumValue<SearchRangeType>> SearchRangeParameter => (ValueParameter<EnumValue<SearchRangeType>>)Parameters["SearchRange"];
80    public ValueParameter<DoubleValue> DirectedRangeStepSizeParameter => (ValueParameter<DoubleValue>)Parameters["DirectedRangeStepSize"];
81    public ValueParameter<IntValue> DirectedRangeRangeParameter => (ValueParameter<IntValue>)Parameters["DirectedRangeRange"];
82    public ValueParameter<EnumValue<SamplingType>> SamplingParameter => (ValueParameter<EnumValue<SamplingType>>)Parameters["Sampling"];
83    public ValueParameter<IntValue> SampleCountParameter => (ValueParameter<IntValue>)Parameters["SampleCount"];
84    public ValueParameter<EnumValue<SamplingPointsType>> SamplingPointsParameter => (ValueParameter<EnumValue<SamplingPointsType>>)Parameters["SamplingPoints"];
85    public ValueParameter<BoolValue> CountSamplesAsEvaluationsParameter => (ValueParameter<BoolValue>)Parameters["CountSamplesAsEvaluations"];
86    public ValueParameter<BoolValue> CountCacheHitsAsEvaluationsParameter => (ValueParameter<BoolValue>)Parameters["CountCacheHitsAsEvaluations"];
87
88    public LookupParameter<IntValue> EvaluatedSolutionsParameter => (LookupParameter<IntValue>)Parameters["EvaluatedSolutions"];
89    #endregion
90
91    private IDictionary<Tuple<int, int>, double> cache;
92
93    public SamplingSegmentOptimizationManipulator() {
94      Parameters.Add(new ValueParameter<EnumValue<DimensionType>>("Dimension", new EnumValue<DimensionType>(DimensionType.All)));
95      Parameters.Add(new ValueParameter<EnumValue<SearchRangeType>>("SearchRange", new EnumValue<SearchRangeType>(SearchRangeType.Full)));
96      Parameters.Add(new ValueParameter<DoubleValue>("DirectedRangeStepSize", new DoubleValue(1.5)));
97      Parameters.Add(new ValueParameter<IntValue>("DirectedRangeRange", new IntValue(5)));
98      Parameters.Add(new ValueParameter<EnumValue<SamplingType>>("Sampling", new EnumValue<SamplingType>(SamplingType.Exhaustive)));
99      Parameters.Add(new ValueParameter<IntValue>("SampleCount")); // only used when sampling != Exhaustive
100      Parameters.Add(new ValueParameter<EnumValue<SamplingPointsType>>("SamplingPoints", new EnumValue<SamplingPointsType>(SamplingPointsType.BeforeCombinations | SamplingPointsType.AfterCombinations)));
101      Parameters.Add(new ValueParameter<BoolValue>("CountSamplesAsEvaluations", new BoolValue(false)));
102      Parameters.Add(new ValueParameter<BoolValue>("CountCacheHitsAsEvaluations", new BoolValue(true)));
103      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions"));
104    }
105    public SamplingSegmentOptimizationManipulator(SamplingSegmentOptimizationManipulator original, Cloner cloner)
106      : base(original, cloner) { }
107    public override IDeepCloneable Clone(Cloner cloner) {
108      return new SamplingSegmentOptimizationManipulator(this, cloner);
109    }
110
111    [StorableConstructor]
112    public SamplingSegmentOptimizationManipulator(StorableConstructorFlag _) : base(_) { }
113    [StorableHook(HookType.AfterDeserialization)]
114    private void AfterDeserialization() {
115      if (Parameters.ContainsKey("SlopeCalculationRange"))
116        Parameters.Remove("SlopeCalculationRange");
117      if (!Parameters.ContainsKey("DirectedRangeStepSize"))
118        Parameters.Add(new ValueParameter<DoubleValue>("DirectedRangeStepSize", new DoubleValue(1.5)));
119      if (!Parameters.ContainsKey("DirectedRangeRange"))
120        Parameters.Add(new ValueParameter<IntValue>("DirectedRangeRange", new IntValue(5)));
121      if (!Parameters.ContainsKey("CountCacheHitsAsEvaluations"))
122        Parameters.Add(new ValueParameter<BoolValue>("CountCacheHitsAsEvaluations", new BoolValue(true)));
123
124    }
125
126    protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) {
127      var solution = new IntegerVector(new[] { integerVector.Min(), integerVector.Max() });
128
129      var indices = CreateIndices(random, solution, bounds, Dimension, SearchRange, EvaluateCached, true,
130        this.DirectedRangeStepSize, this.DirectedRangeRange);
131     
132      if (SamplingPoints.HasFlag(SamplingPointsType.BeforeCombinations))
133        indices = indices.Select(i => SampleIndices(i, Sampling, random, SampleCount).ToList()).ToArray();
134
135      var solutions = CreateCombinations(indices[0], indices[1]);
136      if (!solutions.Any()) {
137        //if (SamplingPoints.HasFlag(SamplingPointsType.BeforeCombinations))
138          return; // no valid combinations -> no mutation
139        //throw new InvalidOperationException("no indices!");
140      }
141
142      if (SamplingPoints.HasFlag(SamplingPointsType.AfterCombinations))
143        solutions = SampleIndices(solutions, Sampling, random, SampleCount);
144
145      //if (CountSamplesAsEvaluationsParameter.Value.Value) {
146      //  int moves = solutions.Count();
147      //  EvaluatedSolutionsParameter.ActualValue.Value += moves - 1;
148      //}
149
150      var best = FindBest(solutions, EvaluateCached);
151      if (best != null) {
152        CopyTo(best.Item1, integerVector);
153      }
154    }
155
156    private double EvaluateCached(IntegerVector solution) {
157      if (cache == null) cache = new Dictionary<Tuple<int, int>, double>();
158      var key = Tuple.Create(solution.Min(), solution.Max());
159      if (cache.TryGetValue(key, out double cachedQuality)) {
160        if (CountSamplesAsEvaluationsParameter.Value.Value && CountCacheHitsAsEvaluationsParameter.Value.Value)
161          EvaluatedSolutionsParameter.ActualValue.Value += 1;
162        return cachedQuality;
163      }
164      var quality = Evaluate(solution);
165      if (CountSamplesAsEvaluationsParameter.Value.Value)
166        EvaluatedSolutionsParameter.ActualValue.Value += 1;
167      cache.Add(key, quality);
168      return quality;
169    }
170   
171    public static IEnumerable<int>[] CreateIndices(IRandom random, IntegerVector integerVector, IntMatrix bounds, DimensionType dimension, SearchRangeType indexRange, Func<IntegerVector, double> evaluate, bool minimize,
172      double directedRangeStepSize, int directedRangeRange) {
173      var indices = new IEnumerable<int>[integerVector.Length];
174      int targetIndex = random.Next(indices.Length); // first or second index
175      for (int i = 0; i < indices.Length; i++) {
176        var searchRange = dimension == DimensionType.All || targetIndex == i ? indexRange : SearchRangeType.None;
177        indices[i] = CreateSingleIndices(integerVector, i, bounds, searchRange, evaluate, minimize, random, directedRangeStepSize, directedRangeRange).ToList();
178        if (!indices[i].Any()) {
179          //throw new InvalidOperationException("no indices!");
180          indices[i] = new[] { integerVector[i] };
181        }
182      }
183      return indices;
184    }
185
186    public static IEnumerable<int> CreateSingleIndices(IntegerVector integerVector, int dim, IntMatrix bounds, SearchRangeType searchRange, Func<IntegerVector, double> evaluate, bool minimize, IRandom random,
187      double directedRangeStepSize, int directedRangeRange) {
188      int currentIndex = integerVector[dim];
189      int length = bounds[dim % bounds.Rows, 1];
190      switch (searchRange) {
191        case SearchRangeType.Full:
192          return Enumerable.Range(0, length);
193        case SearchRangeType.None:
194          return new[] { currentIndex };
195        case SearchRangeType.RandomDirection: // including currentIndex
196          return random.Next(2) == 0
197            ? Enumerable.Range(0, currentIndex + 1) // left
198            : Enumerable.Range(currentIndex, length - currentIndex); // right
199        case SearchRangeType.RandomRange: {
200          // random range around current index, not completely random range
201          int start = random.Next(0, currentIndex + 1), end = random.Next(currentIndex, length);
202          return Enumerable.Range(start, end - start + 1);
203        }
204        case SearchRangeType.DirectedDirection: {
205          var slope = CalculateSlope(integerVector, dim, evaluate);
206          if (!minimize) slope = -slope;
207          return slope > 0 // assume minimization: positive slope -> try lower indices to reduce objective
208            ? Enumerable.Range(0, currentIndex + 1) // left
209            : Enumerable.Range(currentIndex, length - currentIndex); // right
210        }
211        case SearchRangeType.DirectedRange: {
212          var slope = CalculateSlope(integerVector, dim, evaluate);
213          if (!minimize) slope = -slope;
214         
215          double stepSize = directedRangeStepSize;
216          int range = directedRangeRange;
217
218          double target = currentIndex - stepSize * slope;
219          int targetStart = (int)Math.Round(target - range / 2.0);
220          int targetEnd = (int)Math.Round(target + range / 2.0);
221
222          int start = Limit(targetStart, 0, currentIndex + 1);
223          int end = Limit(targetEnd, currentIndex, length);
224          return Enumerable.Range(start, end - start + 1);
225        }
226        default:
227          throw new ArgumentOutOfRangeException(nameof(searchRange), searchRange, null);
228      }
229    }
230
231    private static double Limit(int x, double min, double max) { return Math.Min(Math.Max(x, min), max); }
232    private static int Limit(int x, int min, int max) { return Math.Min(Math.Max(x, min), max); }
233
234    private static double CalculateSlope(IntegerVector position, int dim, Func<IntegerVector, double> evaluate) {
235      double f(int i) {
236        var modified = new IntegerVector(position);
237        modified[dim] = i;
238        return evaluate(modified);
239      }
240     
241      int x = position[dim];
242      var slope = ( // five-point stencil with h = 1
243        + 1 * f(x - 2)
244        - 8 * f(x - 1)
245        + 8 * f(x + 1)
246        - 1 * f(x + 2)
247      ) / 12;
248
249      return slope;
250    }
251
252    public static IEnumerable<IntegerVector> CreateCombinations(IEnumerable<int> startIndices, IEnumerable<int> endIndices) {
253      return
254        from s in startIndices
255        from e in endIndices
256        where s < e
257        select new IntegerVector(new [] { s, e });
258    }
259
260    public static IEnumerable<T> SampleIndices<T>(IEnumerable<T> indices, SamplingType sampling, IRandom random, int count) {
261      switch (sampling) {
262        case SamplingType.Exhaustive:
263          return indices;
264        case SamplingType.RandomSampling:
265          return indices.SampleRandomWithoutRepetition(random, count);
266        case SamplingType.LinearSelection:
267          var indicesList = indices.ToList();
268          // if single sample, the last is always returned
269          var selected = MathNet.Numerics.Generate.LinearSpaced(count, 0, indicesList.Count - 1) // LinearSpaced stop is inclusive
270            .Select(i => (int)Math.Floor(i))
271            .Distinct();
272          return selected.Select(i => indicesList[i]);
273        default:
274          throw new ArgumentOutOfRangeException(nameof(sampling), sampling, null);
275      }
276    }
277
278    public static Tuple<T, double> FindBest<T>(IEnumerable<T> solutions, Func<T, double> evaluate, bool minimize = true) {
279      var evaluatedSolutions = solutions.Select(s => Tuple.Create(s, evaluate(s)));
280      var sorted = evaluatedSolutions.OrderBy(t => t.Item2);
281      return minimize ? sorted.FirstOrDefault() : sorted.LastOrDefault();
282    }
283
284    private static void CopyTo(IntegerVector source, IntegerVector target) {
285      for (int i = 0; i < target.Length; i++)
286        target[i] = source[i];
287    }
288  }
289}
Note: See TracBrowser for help on using the repository browser.