Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2665 Added IsNoop to Expression, Made Expressions storable, Fixed Debugger, Fixed and improved problem data and result visualisation, Added custom ErcOption view, Added problem difficulty to problem data name

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