Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Problem/BenchmarkSuite/PushBenchmarkSuiteEvaluator.cs @ 15189

Last change on this file since 15189 was 15189, checked in by pkimmesw, 7 years ago

#2665 Fixed small issues, testet benchmark suite, added INX Expressions

File size: 12.8 KB
Line 
1namespace HeuristicLab.Problems.ProgramSynthesis.Push.Problem.BenchmarkSuite {
2  using System;
3  using System.Collections.Generic;
4  using System.Globalization;
5  using System.Linq;
6
7  using Common;
8  using Core;
9  using Expressions;
10
11  using HeuristicLab.BenchmarkSuite;
12  using HeuristicLab.Parameters;
13  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
14  using HeuristicLab.Problems.ProgramSynthesis.Push.Configuration;
15  using HeuristicLab.Problems.ProgramSynthesis.Push.Constants;
16
17  using Interpreter;
18  using Problem;
19  using Stack;
20
21  [StorableClass]
22  public class PushBenchmarkSuiteEvaluator : ParameterizedNamedItem, IPushEvaluator {
23
24    private const string DataBoundsParameterName = "DataBounds";
25    private const string DataParameterName = "Data";
26    private const string DataParameterDescription = "Program Synthesis";
27
28    public PushBenchmarkSuiteEvaluator() {
29      Parameters.Add(new FixedValueParameter<DataBounds>(DataBoundsParameterName));
30
31      Parameters.Add(new ValueParameter<ProblemData>(
32        DataParameterName,
33        DataParameterDescription));
34    }
35
36    public PushBenchmarkSuiteEvaluator(ProblemData data) : this() {
37      LoadData(data);
38    }
39
40    [StorableConstructor]
41    public PushBenchmarkSuiteEvaluator(bool deserializing) : base(deserializing) { }
42
43    public PushBenchmarkSuiteEvaluator(PushBenchmarkSuiteEvaluator origin, Cloner cloner) : base(origin, cloner) {
44      Data = cloner.Clone(origin.Data);
45    }
46
47    public override IDeepCloneable Clone(Cloner cloner) {
48      return new PushBenchmarkSuiteEvaluator(this, cloner);
49    }
50
51    public IValueParameter<ProblemData> DataParameter
52    {
53      get { return (IValueParameter<ProblemData>)Parameters[DataParameterName]; }
54    }
55
56    public ProblemData Data
57    {
58      get { return DataParameter.Value; }
59      set { DataParameter.Value = value; }
60    }
61
62    public IValueParameter<DataBounds> DataBoundsParameter
63    {
64      get { return (IValueParameter<DataBounds>)Parameters[DataBoundsParameterName]; }
65    }
66
67    public DataBounds DataBounds
68    {
69      get { return DataBoundsParameter.Value; }
70      set { DataBoundsParameter.Value = value; }
71    }
72
73    public void LoadData(ProblemData data) {
74      Data = data;
75
76      DataBounds.TrainingRange.Start = 0;
77      DataBounds.TrainingRange.End = Data.TrainingCount;
78      DataBounds.TestRange.Start = Data.TrainingCount;
79      DataBounds.TestRange.End = Data.TrainingCount + Data.TestCount;
80    }
81
82    public EvaluationResult Evaluate(IPushInterpreter interpreter, PushProgram program, int start, int end) {
83      var length = end - start;
84      if (length <= 0) return null;
85
86      var evaluationResult = new EvaluationResult(length);
87
88      for (var i = start; i < end; i++) {
89        var result = Evaluate(interpreter, program, i);
90        evaluationResult.ExampleQualities[i - start] = result;
91        evaluationResult.AvgQuality += result;
92        interpreter.Reset();
93      }
94
95      evaluationResult.AvgQuality /= length;
96
97      return evaluationResult;
98    }
99
100    public EvaluationResult EvaluateTest(IPushInterpreter interpreter, PushProgram program) {
101      return Evaluate(interpreter, program, DataBounds.TestRange.Start, DataBounds.TestRange.End);
102    }
103
104    public EvaluationResult EvaluateTest(IReadOnlyPushConfiguration config, PushProgram program, IRandom random) {
105      var interpreter = new PushInterpreter(config, random);
106      return EvaluateTest(interpreter, program);
107    }
108
109    public EvaluationResult EvaluateTest(PushInterpreterPool pool, PushProgram program, IRandom random) {
110      using (var interpreter = pool.Create(random)) {
111        return EvaluateTest(interpreter, program);
112      }
113    }
114
115    public EvaluationResult EvaluateTraining(IPushInterpreter interpreter, PushProgram program) {
116      return Evaluate(interpreter, program, DataBounds.TrainingRange.Start, DataBounds.TrainingRange.End);
117    }
118
119    public EvaluationResult EvaluateTraining(IReadOnlyPushConfiguration config, PushProgram program, IRandom random) {
120      var interpreter = new PushInterpreter(config, random);
121      return EvaluateTraining(interpreter, program);
122    }
123
124    public EvaluationResult EvaluateTraining(PushInterpreterPool pool, PushProgram program, IRandom random) {
125      using (var interpreter = pool.Create(random)) {
126        return EvaluateTraining(interpreter, program);
127      }
128    }
129
130    public double Evaluate(IPushInterpreter interpreter, PushProgram program, int exampleIndex) {
131      var example = Data.Examples[exampleIndex];
132
133      //interpreter.BooleanStack.Push(example.InputBoolean);
134      //interpreter.IntegerStack.Push(example.InputInteger);
135      //interpreter.FloatStack.Push(example.InputFloat);
136      //interpreter.CharStack.Push(example.InputChar);
137      //interpreter.StringStack.Push(example.InputString);
138      //interpreter.StringVectorStack.Push(example.InputStringVector);
139      //interpreter.IntegerVectorStack.Push(example.InputIntegerVector);
140      //interpreter.FloatVectorStack.Push(example.InputFloatVector);
141
142      interpreter.SetInput(
143        integers: example.InputInteger,
144        floats: example.InputFloat,
145        booleans: example.InputBoolean,
146        chars: example.InputChar,
147        strings: example.InputString,
148        integerVectors: example.InputIntegerVector,
149        floatVectors: example.InputFloatVector,
150        stringVectors: example.InputStringVector);
151
152      interpreter.Run(program);
153
154      switch (Data.ProblemType) {
155        case ProblemType.NumberIO: return NumberIo(interpreter, example);
156        case ProblemType.Median: return Median(interpreter, example);
157      }
158
159      return Default(interpreter, example);
160    }
161
162    private double Default(IPushInterpreter interpreter, Example example) {
163      var result = GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer)
164             + GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision))
165             + GetDiff(example.OutputBoolean, interpreter.BooleanStack, Data.WorstResult, BooleanDiffer)
166             + GetDiff(example.OutputString, interpreter.StringStack, Data.WorstResult, StringDiffer)
167             + GetDiff(example.OutputChar, interpreter.CharStack, Data.WorstResult, CharDiffer)
168             + GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, example.OutputPrintLineCount, Data.WorstResult)
169             + GetVectorDiff(example.OutputIntegerVector, interpreter.IntegerVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, IntegerDiffer))
170             + GetVectorDiff(example.OutputFloatVector, interpreter.FloatVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, (x, y) => FloatDiffer(x, y, example.OutputFloatVectorPrecision)))
171             + GetVectorDiff(example.OutputStringVector, interpreter.StringVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, StringDiffer));
172
173      return result;
174    }
175
176    private double Median(IPushInterpreter interpreter, Example example) {
177      return interpreter.PrintStack.IsEmpty || !interpreter.PrintStack.Top.Equals(example.OutputPrint) ? 1 : 0;
178    }
179
180    private double NumberIo(IPushInterpreter interpreter, Example example) {
181      if (interpreter.PrintStack.IsEmpty)
182        return Data.WorstResult;
183
184      double value;
185      if (double.TryParse(interpreter.PrintStack.Top, NumberStyles.Number | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) {
186        var diff = Math.Abs(example.OutputFloat[0] - value);
187        var result = Math.Min(diff, Data.WorstResult);
188
189        return result;
190      }
191
192      var penaltyError = Data.WorstResult / 4.0d;
193      var levenshteinDistance = GetPrintDiffer(
194        example.OutputPrint,
195        interpreter.PrintStack.Top,
196        Data.WorstResult);
197
198      return levenshteinDistance + penaltyError;
199    }
200
201    private static double FloatDiffer(double a, double b, int digits) {
202      var result = Math.Round(a, digits) - Math.Round(b, digits);
203
204      // ReSharper disable once CompareOfFloatsByEqualityOperator
205      if (result == double.MinValue || double.IsPositiveInfinity(result) || double.IsNaN(result))
206        return double.MaxValue;
207
208      // ReSharper disable once CompareOfFloatsByEqualityOperator
209      if (result == double.MaxValue || double.IsNegativeInfinity(result))
210        return double.MinValue;
211
212      return Math.Abs(result);
213    }
214
215    private static double IntegerDiffer(long a, long b) {
216      var result = a - b;
217
218      return result == long.MinValue ? long.MaxValue : Math.Abs(result);
219    }
220
221    private static double BooleanDiffer(bool a, bool b) {
222      return a == b ? 0 : 1;
223    }
224
225    private static double StringDiffer(string a, string b) {
226      return LevenshteinDistance(a, b);
227    }
228
229    private static double CharDiffer(char a, char b) {
230      return IntegerDiffer(a, b);
231    }
232
233    private static double VectorDiffer<T>(IReadOnlyList<T> estimated, IReadOnlyList<T> outcome, Func<T, T, double> differ) {
234      var length = Math.Min(estimated.Count, outcome.Count);
235      var result = 0d;
236
237      for (var i = 0; i < length; i++) {
238        result += differ(estimated[i], outcome[i]);
239      }
240
241      if (estimated.Count > outcome.Count) {
242        var remainingLength = estimated.Count - length;
243        for (var i = 0; i < remainingLength; i++)
244          result += differ(estimated[i], default(T));
245      }
246
247      return result;
248    }
249
250    private static double GetPrintDiffer(string estimated, string printResult, double worstResult) {
251      var distance = LevenshteinDistance(estimated, printResult);
252
253      return Math.Min(distance, worstResult);
254    }
255
256    private static double GetPrintDiffer(string estimated, IPushStack<string> printStack, int estimatedCount, double worstResult) {
257      var printResult = string.Join(PushEnvironment.NewLine, printStack.AsStrings().Take(estimatedCount));
258      var distance = LevenshteinDistance(estimated, printResult);
259
260      return Math.Min(distance, worstResult);
261    }
262
263    private static double GetVectorDiff<T>(IReadOnlyList<IReadOnlyList<T>> estimated, IPushStack<IReadOnlyList<T>> resultStack, double worstResult, Func<IReadOnlyList<T>, IReadOnlyList<T>, double> differ)
264      where T : IComparable {
265      if (estimated.Count == 0) return 0d;
266
267      var diff = 0d;
268      var comparableLength = 0;
269
270      if (!resultStack.IsEmpty) {
271        var count = Math.Min(estimated.Count, resultStack.Count);
272        var result = resultStack.Peek(count);
273        comparableLength = Math.Min(estimated.Count, result.Count);
274
275        for (var i = 0; i < comparableLength; i++) {
276          diff += Math.Min(differ(estimated[i], result[i]), worstResult);
277        }
278      }
279
280      var emptyTArray = new T[0];
281      for (var i = comparableLength; i < estimated.Count - comparableLength; i++) {
282        diff += differ(estimated[i], emptyTArray);
283      }
284
285      return diff;
286    }
287
288    private static double GetDiff<T>(IReadOnlyList<T> estimated, IPushStack<T> resultStack, double worstResult, Func<T, T, double> differ)
289      where T : IComparable {
290      if (estimated.Count == 0) return 0d;
291
292      var diff = 0d;
293      var comparableLength = 0;
294
295      if (!resultStack.IsEmpty) {
296        var count = Math.Min(estimated.Count, resultStack.Count);
297        var result = resultStack.Peek(count);
298        comparableLength = Math.Min(estimated.Count, result.Count);
299
300        for (var i = 0; i < comparableLength; i++) {
301          diff += Math.Min(differ(estimated[i], result[i]), worstResult);
302        }
303      }
304
305      for (var i = comparableLength; i < estimated.Count - comparableLength; i++) {
306        diff += differ(estimated[i], default(T));
307      }
308
309      return diff;
310    }
311
312    /// <summary>
313    /// https://www.dotnetperls.com/levenshtein
314    /// </summary>
315    private static int LevenshteinDistance(string source, string target) {
316      if (source == null && target == null) return 0;
317      if (source == null) return target.Length;
318      if (target == null) return source.Length;
319
320      int n = source.Length;
321      int m = target.Length;
322      int[,] d = new int[n + 1, m + 1];
323
324      // Step 1
325      if (n == 0) {
326        return m;
327      }
328
329      if (m == 0) {
330        return n;
331      }
332
333      // Step 2
334      for (int i = 0; i <= n; d[i, 0] = i++) {
335      }
336
337      for (int j = 0; j <= m; d[0, j] = j++) {
338      }
339
340      // Step 3
341      for (int i = 1; i <= n; i++) {
342        //Step 4
343        for (int j = 1; j <= m; j++) {
344          // Step 5
345          int cost = (target[j - 1] == source[i - 1]) ? 0 : 1;
346
347          // Step 6
348          d[i, j] = Math.Min(
349              Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
350              d[i - 1, j - 1] + cost);
351        }
352      }
353      // Step 7
354      return d[n, m];
355    }
356  }
357}
Note: See TracBrowser for help on using the repository browser.