Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SegmentOptimization/SegmentOptimizationProblem.cs @ 18230

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

#3040 Changed SubVector symbol to include end-index in result.

File size: 12.7 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 System.Linq.Expressions;
26using HEAL.Attic;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Encodings.IntegerVectorEncoding;
31using HeuristicLab.Optimization;
32using HeuristicLab.Parameters;
33using HeuristicLab.PluginInfrastructure;
34using HeuristicLab.Problems.Instances;
35using HeuristicLab.Problems.Instances.Types;
36
37using DoubleVector = MathNet.Numerics.LinearAlgebra.Vector<double>;
38
39namespace HeuristicLab.Problems.DataAnalysis.Symbolic.SegmentOptimization {
40  [Item("Segment Optimization Problem (SOP)", "")]
41  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 1200)]
42  [StorableType("64107939-34A7-4530-BFAB-8EA1C321BF6F")]
43  public class SegmentOptimizationProblem : SingleObjectiveBasicProblem<IntegerVectorEncoding>, IProblemInstanceConsumer<SOPData> {
44
45    [StorableType("63243591-5A56-41A6-B079-122B83583993")]
46    public enum Aggregation {
47      Sum,
48      Mean,
49      StandardDeviation
50    }
51
52    public override bool Maximization => false;
53
54    [Storable]
55    private IValueParameter<DoubleMatrix> dataParameter;
56    public IValueParameter<DoubleMatrix> DataParameter {
57      get { return dataParameter; }
58    }
59    [Storable]
60    private IValueParameter<IntRange> knownBoundsParameter;
61    public IValueParameter<IntRange> KnownBoundsParameter {
62      get { return knownBoundsParameter; }
63    }
64    [Storable]
65    private IValueParameter<EnumValue<Aggregation>> aggregationParameter;
66    public IValueParameter<EnumValue<Aggregation>> AggregationParameter {
67      get { return aggregationParameter; }
68    }
69   
70    public SegmentOptimizationProblem() {
71      Encoding = new IntegerVectorEncoding("bounds");
72
73      Parameters.Add(dataParameter = new ValueParameter<DoubleMatrix>("Data", ""));
74      Parameters.Add(knownBoundsParameter = new ValueParameter<IntRange>("Known Bounds", ""));
75      Parameters.Add(aggregationParameter = new ValueParameter<EnumValue<Aggregation>>("Aggregation Function", ""));
76
77      RegisterEventHandlers();
78
79      #region Default Instance
80      Load(new SOPData() {
81        Data = ToNdimArray(Enumerable.Range(1, 50).Select(x => (double)x * x).ToArray()),
82        Lower = 20, Upper = 30,
83        Aggregation = "mean"
84      });
85      #endregion
86
87      var optMutators = ApplicationManager.Manager.GetInstances<SegmentOptimizationMutator>();
88      Encoding.ConfigureOperators(optMutators);
89      Operators.AddRange(optMutators);
90    }
91    private SegmentOptimizationProblem(SegmentOptimizationProblem original, Cloner cloner)
92      : base(original, cloner) {
93      dataParameter = cloner.Clone(original.dataParameter);
94      knownBoundsParameter = cloner.Clone(original.knownBoundsParameter);
95      aggregationParameter = cloner.Clone(original.aggregationParameter);
96
97      RegisterEventHandlers();
98    }
99    public override IDeepCloneable Clone(Cloner cloner) {
100      return new SegmentOptimizationProblem(this, cloner);
101    }
102
103    [StorableConstructor]
104    private SegmentOptimizationProblem(StorableConstructorFlag _) : base(_) { }
105    [StorableHook(HookType.AfterDeserialization)]
106    private void AfterDeserialization() {
107      if (Parameters.ContainsKey("Data Vector") && Parameters["Data Vector"] is ValueParameter<DoubleArray> arrayParameter) {
108        Parameters.Remove(arrayParameter);
109        var array = arrayParameter.Value;
110        var matrix = new DoubleMatrix(1, array.Length);
111        for (int i = 0; i < array.Length; i++) matrix[0, i] = array[i];
112        Parameters.Add(dataParameter = new ValueParameter<DoubleMatrix>("Data", "", matrix));
113      }
114
115      RegisterEventHandlers();
116    }
117   
118    private void RegisterEventHandlers() {
119      dataParameter.ValueChanged += DataChanged;
120      knownBoundsParameter.ValueChanged += KnownBoundsChanged;
121      aggregationParameter.Value.ValueChanged += AggregationFunctionChanged;
122    }
123    private void DataChanged(object sender, EventArgs eventArgs) {
124      Encoding.Bounds = new IntMatrix(new[,] { { 0, DataParameter.Value.Columns } });
125    }
126    private void KnownBoundsChanged(object sender, EventArgs e) {
127    }
128    private void AggregationFunctionChanged(object sender, EventArgs eventArgs) {
129    }
130
131    public override double Evaluate(Individual individual, IRandom random) {
132      var data = DataParameter.Value;
133      var knownBounds = KnownBoundsParameter.Value;
134      var aggregation = aggregationParameter.Value.Value;
135      var solution = individual.IntegerVector(Encoding.Name);
136      return Evaluate(solution, data, knownBounds, aggregation);
137    }
138
139    public static double Evaluate(IntegerVector solution, DoubleMatrix data, IntRange knownBounds, Aggregation aggregation) {
140      var bounds = new IntRange(solution.Min(), solution.Max());
141      double target = BoundedAggregation(data, knownBounds, aggregation);
142      double prediction = BoundedAggregation(data, bounds, aggregation);
143      return Math.Pow(target - prediction, 2);
144    }
145
146    public override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) {
147      var orderedIndividuals = individuals.Zip(qualities, (i, q) => new { Individual = i, Quality = q }).OrderBy(z => z.Quality);
148      var best = Maximization ? orderedIndividuals.Last().Individual.IntegerVector(Encoding.Name) : orderedIndividuals.First().Individual.IntegerVector(Encoding.Name);
149
150      var bounds = new IntRange(best.Min(), best.Max());
151
152      var data = DataParameter.Value;
153      var knownBounds = KnownBoundsParameter.Value;
154      var aggregation = aggregationParameter.Value.Value;
155
156      double target = BoundedAggregation(data, knownBounds, aggregation);
157      double prediction = BoundedAggregation(data, bounds, aggregation);
158      double diff = target - prediction;
159
160      if (results.TryGetValue("AggValue Diff", out var oldDiffResult)) {
161        var oldDiff = (DoubleValue)oldDiffResult.Value;
162        if (Math.Abs(oldDiff.Value) < Math.Abs(diff)) return;
163      }
164
165      results.AddOrUpdateResult("Bounds", bounds);
166
167      results.AddOrUpdateResult("AggValue Diff", new DoubleValue(diff));
168      results.AddOrUpdateResult("AggValue Squared Diff", new DoubleValue(Math.Pow(diff, 2)));
169
170      results.AddOrUpdateResult("Lower Diff", new IntValue(knownBounds.Start - bounds.Start));
171      results.AddOrUpdateResult("Upper Diff", new IntValue(knownBounds.End - bounds.End));
172      results.AddOrUpdateResult("Length Diff", new IntValue(knownBounds.Size - bounds.Size));
173    }
174
175    //private static double BoundedAggregation(DoubleArray data, IntRange bounds, Aggregation aggregation) {
176    //  var matrix = new DoubleMatrix(1, data.Length);
177    //  for (int i = 0; i < data.Length; i++) matrix[0, i] = data[i];
178    //  return BoundedAggregation(matrix, bounds, aggregation);
179    //}
180
181    private static double BoundedAggregation(DoubleMatrix data, IntRange bounds, Aggregation aggregation) {
182      //if (bounds.Size == 0) {
183      //  return 0;
184      //}
185
186      var resultValues = new double[data.Rows];
187      for (int row = 0; row < data.Rows; row++) {
188        var vector = data.GetRow(row);
189        var segment = vector.Skip(bounds.Start).Take(bounds.Size + 1); // exclusive end
190        switch (aggregation) {
191          case Aggregation.Sum:
192            resultValues[row] = segment.Sum();
193            break;
194          case Aggregation.Mean:
195            resultValues[row] = segment.Average();
196            break;
197          case Aggregation.StandardDeviation:
198            resultValues[row] = segment.StandardDeviationPop();
199            break;
200          default:
201            throw new NotImplementedException();
202        }
203      }
204
205      return resultValues.Average();
206    }
207
208    public void Load(SOPData data) {
209      DataParameter.Value = new DoubleMatrix(data.Data);
210      KnownBoundsParameter.Value = new IntRange(data.Lower, data.Upper);
211      switch (data.Aggregation.ToLower()) {
212        case "sum":
213          AggregationParameter.Value.Value = Aggregation.Sum;
214          break;
215        case "mean":
216        case "avg":
217          AggregationParameter.Value.Value = Aggregation.Mean;
218          break;
219        case "standarddeviation":
220        case "std":
221        case "sd":
222          AggregationParameter.Value.Value = Aggregation.StandardDeviation;
223          break;
224        default:
225          throw new NotSupportedException();
226      }
227                                           
228      Encoding.Length = 2;
229      Encoding.Bounds = new IntMatrix(new[,] { { 0, DataParameter.Value.Columns } });
230
231      BestKnownQuality = 0;
232
233      Name = data.Name;
234      Description = data.Description;
235    }
236
237    public static T[,] ToNdimArray<T>(T[] array) {
238      var matrix = new T[1, array.Length];
239      for (int i = 0; i < array.Length; i++)
240        matrix[0, i] = array[i];
241      return matrix;
242    }
243
244    private class DoubleArrayComparer : IEqualityComparer<double[,]> {
245      public bool Equals(double[,] x, double[,] y) {
246        if (ReferenceEquals(x, y)) return true;
247        if (x.Length != y.Length) return false;
248        if (x.GetLength(0) != y.GetLength(0)) return false;
249        if (x.GetLength(1) != y.GetLength(1)) return false;
250
251        int rows = x.GetLength(0), cols = x.GetLength(1);
252        for (int i = 0; i < rows; i++) {
253          for (int j = 0; j < cols; j++) {
254            if (x[i, j] != y[i, j])
255              return false;
256          }
257        }
258
259        return true;
260      }
261
262      public int GetHashCode(double[,] obj) {
263        return GetSequenceHashCode(obj.Cast<double>())/*gives matrix enumerated*/;
264      }
265
266      //https://stackoverflow.com/questions/7278136/create-hash-value-on-a-list
267      public static int GetSequenceHashCode<T>(IEnumerable<T> sequence) {
268        const int seed = 487;
269        const int modifier = 31;
270
271        unchecked {
272          return sequence.Aggregate(seed, (current, item) => (current * modifier) + item.GetHashCode());
273        }
274      }
275    }
276
277    private static readonly Action<DoubleMatrix, double[,]> setValues;
278    private static readonly Func<DoubleMatrix, double[,]> getValues;
279    static SegmentOptimizationProblem() {
280      var dataset = Expression.Parameter(typeof(DoubleMatrix));
281      var variableValues = Expression.Parameter(typeof(double[,]));
282      var valuesExpression = Expression.Field(dataset, "matrix");
283      var assignExpression = Expression.Assign(valuesExpression, variableValues);
284
285      var variableValuesSetExpression = Expression.Lambda<Action<DoubleMatrix, double[,]>>(assignExpression, dataset, variableValues);
286      setValues = variableValuesSetExpression.Compile();
287
288      var variableValuesGetExpression = Expression.Lambda<Func<DoubleMatrix, double[,]>>(valuesExpression, dataset);
289      getValues = variableValuesGetExpression.Compile();
290    }
291
292    public static Tuple<int, int, int> RemoveDuplicateMatrices(IContent content) {
293      int overallTests = 0, removedDuplicated = 0;
294      var mappings = new Dictionary<double[,], double[,]>(new DoubleArrayComparer());
295       foreach (var parameter in content.GetObjectGraphObjects(excludeStaticMembers: true).OfType<DoubleMatrix>()) {
296         var originalValue = getValues(parameter);
297         overallTests++;
298         if (mappings.TryGetValue(originalValue, out var mappedValue)) {
299           setValues(parameter, mappedValue);
300           removedDuplicated++;
301         } else {
302           mappings.Add(originalValue, originalValue);
303         }
304       }
305     
306      int removedQualities = 0;
307      foreach (var run in content.GetObjectGraphObjects(excludeStaticMembers: true).OfType<IRun>()) {
308        if (run.Results.ContainsKey("Qualities")) {
309          run.Results.Remove("Qualities");
310          removedQualities++;
311        }
312      }
313
314      return Tuple.Create(overallTests, removedDuplicated, removedQualities);
315    }
316  }
317}
Note: See TracBrowser for help on using the repository browser.